From: Greg Kroah-Hartman Date: Mon, 15 Apr 2019 11:35:07 +0000 (+0200) Subject: 5.0-stable patches X-Git-Tag: v4.9.169~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51115571b670ad395e6a303bc4aa677addd39f2d;p=thirdparty%2Fkernel%2Fstable-queue.git 5.0-stable patches added patches: asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch asoc-intel-fix-crash-at-suspend-resume-after-failed-codec-registration.patch mm-writeback-use-exact-memcg-dirty-counts.patch --- diff --git a/queue-5.0/asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch b/queue-5.0/asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch new file mode 100644 index 00000000000..5660b4841ee --- /dev/null +++ b/queue-5.0/asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch @@ -0,0 +1,130 @@ +From 0ff4e8c61b794a4bf6c854ab071a1abaaa80f358 Mon Sep 17 00:00:00 2001 +From: "S.j. Wang" +Date: Wed, 27 Feb 2019 06:31:12 +0000 +Subject: ASoC: fsl_esai: fix channel swap issue when stream starts + +From: S.j. Wang + +commit 0ff4e8c61b794a4bf6c854ab071a1abaaa80f358 upstream. + +There is very low possibility ( < 0.1% ) that channel swap happened +in beginning when multi output/input pin is enabled. The issue is +that hardware can't send data to correct pin in the beginning with +the normal enable flow. + +This is hardware issue, but there is no errata, the workaround flow +is that: Each time playback/recording, firstly clear the xSMA/xSMB, +then enable TE/RE, then enable xSMB and xSMA (xSMB must be enabled +before xSMA). Which is to use the xSMA as the trigger start register, +previously the xCR_TE or xCR_RE is the bit for starting. + +Fixes commit 43d24e76b698 ("ASoC: fsl_esai: Add ESAI CPU DAI driver") +Cc: +Reviewed-by: Fabio Estevam +Acked-by: Nicolin Chen +Signed-off-by: Shengjiu Wang +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/fsl/fsl_esai.c | 47 +++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 37 insertions(+), 10 deletions(-) + +--- a/sound/soc/fsl/fsl_esai.c ++++ b/sound/soc/fsl/fsl_esai.c +@@ -54,6 +54,8 @@ struct fsl_esai { + u32 fifo_depth; + u32 slot_width; + u32 slots; ++ u32 tx_mask; ++ u32 rx_mask; + u32 hck_rate[2]; + u32 sck_rate[2]; + bool hck_dir[2]; +@@ -361,21 +363,13 @@ static int fsl_esai_set_dai_tdm_slot(str + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); + +- regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, +- ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); +- regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, +- ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); +- + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); + +- regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, +- ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); +- regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, +- ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); +- + esai_priv->slot_width = slot_width; + esai_priv->slots = slots; ++ esai_priv->tx_mask = tx_mask; ++ esai_priv->rx_mask = rx_mask; + + return 0; + } +@@ -596,6 +590,7 @@ static int fsl_esai_trigger(struct snd_p + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); ++ u32 mask; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +@@ -608,15 +603,38 @@ static int fsl_esai_trigger(struct snd_p + for (i = 0; tx && i < channels; i++) + regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + ++ /* ++ * When set the TE/RE in the end of enablement flow, there ++ * will be channel swap issue for multi data line case. ++ * In order to workaround this issue, we switch the bit ++ * enablement sequence to below sequence ++ * 1) clear the xSMB & xSMA: which is done in probe and ++ * stop state. ++ * 2) set TE/RE ++ * 3) set xSMB ++ * 4) set xSMA: xSMA is the last one in this flow, which ++ * will trigger esai to start. ++ */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); ++ mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; ++ ++ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), ++ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); ++ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ++ ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); ++ + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); ++ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ++ ESAI_xSMA_xS_MASK, 0); ++ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), ++ ESAI_xSMB_xS_MASK, 0); + + /* Disable and reset FIFO */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), +@@ -906,6 +924,15 @@ static int fsl_esai_probe(struct platfor + return ret; + } + ++ esai_priv->tx_mask = 0xFFFFFFFF; ++ esai_priv->rx_mask = 0xFFFFFFFF; ++ ++ /* Clear the TSMA, TSMB, RSMA, RSMB */ ++ regmap_write(esai_priv->regmap, REG_ESAI_TSMA, 0); ++ regmap_write(esai_priv->regmap, REG_ESAI_TSMB, 0); ++ regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0); ++ regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0); ++ + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component, + &fsl_esai_dai, 1); + if (ret) { diff --git a/queue-5.0/asoc-intel-fix-crash-at-suspend-resume-after-failed-codec-registration.patch b/queue-5.0/asoc-intel-fix-crash-at-suspend-resume-after-failed-codec-registration.patch new file mode 100644 index 00000000000..b10b19eb310 --- /dev/null +++ b/queue-5.0/asoc-intel-fix-crash-at-suspend-resume-after-failed-codec-registration.patch @@ -0,0 +1,114 @@ +From 8f71370f4b02730e8c27faf460af7a3586e24e1f Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Fri, 22 Mar 2019 15:39:48 -0700 +Subject: ASoC: intel: Fix crash at suspend/resume after failed codec registration + +From: Guenter Roeck + +commit 8f71370f4b02730e8c27faf460af7a3586e24e1f upstream. + +If codec registration fails after the ASoC Intel SST driver has been probed, +the kernel will Oops and crash at suspend/resume. + +general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI +CPU: 1 PID: 2811 Comm: cat Tainted: G W 4.19.30 #15 +Hardware name: GOOGLE Clapper, BIOS Google_Clapper.5216.199.7 08/22/2014 +RIP: 0010:snd_soc_suspend+0x5a/0xd21 +Code: 03 80 3c 10 00 49 89 d7 74 0b 48 89 df e8 71 72 c4 fe 4c 89 +fa 48 8b 03 48 89 45 d0 48 8d 98 a0 01 00 00 48 89 d8 48 c1 e8 03 +<8a> 04 10 84 c0 0f 85 85 0c 00 00 80 3b 00 0f 84 6b 0c 00 00 48 8b +RSP: 0018:ffff888035407750 EFLAGS: 00010202 +RAX: 0000000000000034 RBX: 00000000000001a0 RCX: 0000000000000000 +RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffff88805c417098 +RBP: ffff8880354077b0 R08: dffffc0000000000 R09: ffffed100b975718 +R10: 0000000000000001 R11: ffffffff949ea4a3 R12: 1ffff1100b975746 +R13: dffffc0000000000 R14: ffff88805cba4588 R15: dffffc0000000000 +FS: 0000794a78e91b80(0000) GS:ffff888068d00000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007bd5283ccf58 CR3: 000000004b7aa000 CR4: 00000000001006e0 +Call Trace: +? dpm_complete+0x67b/0x67b +? i915_gem_suspend+0x14d/0x1ad +sst_soc_prepare+0x91/0x1dd +? sst_be_hw_params+0x7e/0x7e +dpm_prepare+0x39a/0x88b +dpm_suspend_start+0x13/0x9d +suspend_devices_and_enter+0x18f/0xbd7 +? arch_suspend_enable_irqs+0x11/0x11 +? printk+0xd9/0x12d +? lock_release+0x95f/0x95f +? log_buf_vmcoreinfo_setup+0x131/0x131 +? rcu_read_lock_sched_held+0x140/0x22a +? __bpf_trace_rcu_utilization+0xa/0xa +? __pm_pr_dbg+0x186/0x190 +? pm_notifier_call_chain+0x39/0x39 +? suspend_test+0x9d/0x9d +pm_suspend+0x2f4/0x728 +? trace_suspend_resume+0x3da/0x3da +? lock_release+0x95f/0x95f +? kernfs_fop_write+0x19f/0x32d +state_store+0xd8/0x147 +? sysfs_kf_read+0x155/0x155 +kernfs_fop_write+0x23e/0x32d +__vfs_write+0x108/0x608 +? vfs_read+0x2e9/0x2e9 +? rcu_read_lock_sched_held+0x140/0x22a +? __bpf_trace_rcu_utilization+0xa/0xa +? debug_smp_processor_id+0x10/0x10 +? selinux_file_permission+0x1c5/0x3c8 +? rcu_sync_lockdep_assert+0x6a/0xad +? __sb_start_write+0x129/0x2ac +vfs_write+0x1aa/0x434 +ksys_write+0xfe/0x1be +? __ia32_sys_read+0x82/0x82 +do_syscall_64+0xcd/0x120 +entry_SYSCALL_64_after_hwframe+0x49/0xbe + +In the observed situation, the problem is seen because the codec driver +failed to probe due to a hardware problem. + +max98090 i2c-193C9890:00: Failed to read device revision: -1 +max98090 i2c-193C9890:00: ASoC: failed to probe component -1 +cht-bsw-max98090 cht-bsw-max98090: ASoC: failed to instantiate card -1 +cht-bsw-max98090 cht-bsw-max98090: snd_soc_register_card failed -1 +cht-bsw-max98090: probe of cht-bsw-max98090 failed with error -1 + +The problem is similar to the problem solved with commit 2fc995a87f2e +("ASoC: intel: Fix crash at suspend/resume without card registration"), +but codec registration fails at a later point. At that time, the pointer +checked with the above mentioned commit is already set, but it is not +cleared if the device is subsequently removed. Adding a remove function +to clear the pointer fixes the problem. + +Cc: stable@vger.kernel.org +Cc: Jarkko Nikula +Cc: Curtis Malainey +Signed-off-by: Guenter Roeck +Acked-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/intel/atom/sst-mfld-platform-pcm.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c ++++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c +@@ -711,9 +711,17 @@ static int sst_soc_probe(struct snd_soc_ + return sst_dsp_init_v2_dpcm(component); + } + ++static void sst_soc_remove(struct snd_soc_component *component) ++{ ++ struct sst_data *drv = dev_get_drvdata(component->dev); ++ ++ drv->soc_card = NULL; ++} ++ + static const struct snd_soc_component_driver sst_soc_platform_drv = { + .name = DRV_NAME, + .probe = sst_soc_probe, ++ .remove = sst_soc_remove, + .ops = &sst_platform_ops, + .compr_ops = &sst_platform_compr_ops, + .pcm_new = sst_pcm_new, diff --git a/queue-5.0/mm-writeback-use-exact-memcg-dirty-counts.patch b/queue-5.0/mm-writeback-use-exact-memcg-dirty-counts.patch new file mode 100644 index 00000000000..ef0b1f0de83 --- /dev/null +++ b/queue-5.0/mm-writeback-use-exact-memcg-dirty-counts.patch @@ -0,0 +1,223 @@ +From 0b3d6e6f2dd0a7b697b1aa8c167265908940624b Mon Sep 17 00:00:00 2001 +From: Greg Thelen +Date: Fri, 5 Apr 2019 18:39:18 -0700 +Subject: mm: writeback: use exact memcg dirty counts + +From: Greg Thelen + +commit 0b3d6e6f2dd0a7b697b1aa8c167265908940624b upstream. + +Since commit a983b5ebee57 ("mm: memcontrol: fix excessive complexity in +memory.stat reporting") memcg dirty and writeback counters are managed +as: + + 1) per-memcg per-cpu values in range of [-32..32] + + 2) per-memcg atomic counter + +When a per-cpu counter cannot fit in [-32..32] it's flushed to the +atomic. Stat readers only check the atomic. Thus readers such as +balance_dirty_pages() may see a nontrivial error margin: 32 pages per +cpu. + +Assuming 100 cpus: + 4k x86 page_size: 13 MiB error per memcg + 64k ppc page_size: 200 MiB error per memcg + +Considering that dirty+writeback are used together for some decisions the +errors double. + +This inaccuracy can lead to undeserved oom kills. One nasty case is +when all per-cpu counters hold positive values offsetting an atomic +negative value (i.e. per_cpu[*]=32, atomic=n_cpu*-32). +balance_dirty_pages() only consults the atomic and does not consider +throttling the next n_cpu*32 dirty pages. If the file_lru is in the +13..200 MiB range then there's absolutely no dirty throttling, which +burdens vmscan with only dirty+writeback pages thus resorting to oom +kill. + +It could be argued that tiny containers are not supported, but it's more +subtle. It's the amount the space available for file lru that matters. +If a container has memory.max-200MiB of non reclaimable memory, then it +will also suffer such oom kills on a 100 cpu machine. + +The following test reliably ooms without this patch. This patch avoids +oom kills. + + $ cat test + mount -t cgroup2 none /dev/cgroup + cd /dev/cgroup + echo +io +memory > cgroup.subtree_control + mkdir test + cd test + echo 10M > memory.max + (echo $BASHPID > cgroup.procs && exec /memcg-writeback-stress /foo) + (echo $BASHPID > cgroup.procs && exec dd if=/dev/zero of=/foo bs=2M count=100) + + $ cat memcg-writeback-stress.c + /* + * Dirty pages from all but one cpu. + * Clean pages from the non dirtying cpu. + * This is to stress per cpu counter imbalance. + * On a 100 cpu machine: + * - per memcg per cpu dirty count is 32 pages for each of 99 cpus + * - per memcg atomic is -99*32 pages + * - thus the complete dirty limit: sum of all counters 0 + * - balance_dirty_pages() only sees atomic count -99*32 pages, which + * it max()s to 0. + * - So a workload can dirty -99*32 pages before balance_dirty_pages() + * cares. + */ + #define _GNU_SOURCE + #include + #include + #include + #include + #include + #include + #include + #include + #include + + static char *buf; + static int bufSize; + + static void set_affinity(int cpu) + { + cpu_set_t affinity; + + CPU_ZERO(&affinity); + CPU_SET(cpu, &affinity); + if (sched_setaffinity(0, sizeof(affinity), &affinity)) + err(1, "sched_setaffinity"); + } + + static void dirty_on(int output_fd, int cpu) + { + int i, wrote; + + set_affinity(cpu); + for (i = 0; i < 32; i++) { + for (wrote = 0; wrote < bufSize; ) { + int ret = write(output_fd, buf+wrote, bufSize-wrote); + if (ret == -1) + err(1, "write"); + wrote += ret; + } + } + } + + int main(int argc, char **argv) + { + int cpu, flush_cpu = 1, output_fd; + const char *output; + + if (argc != 2) + errx(1, "usage: output_file"); + + output = argv[1]; + bufSize = getpagesize(); + buf = malloc(getpagesize()); + if (buf == NULL) + errx(1, "malloc failed"); + + output_fd = open(output, O_CREAT|O_RDWR); + if (output_fd == -1) + err(1, "open(%s)", output); + + for (cpu = 0; cpu < get_nprocs(); cpu++) { + if (cpu != flush_cpu) + dirty_on(output_fd, cpu); + } + + set_affinity(flush_cpu); + if (fsync(output_fd)) + err(1, "fsync(%s)", output); + if (close(output_fd)) + err(1, "close(%s)", output); + free(buf); + } + +Make balance_dirty_pages() and wb_over_bg_thresh() work harder to +collect exact per memcg counters. This avoids the aforementioned oom +kills. + +This does not affect the overhead of memory.stat, which still reads the +single atomic counter. + +Why not use percpu_counter? memcg already handles cpus going offline, so +no need for that overhead from percpu_counter. And the percpu_counter +spinlocks are more heavyweight than is required. + +It probably also makes sense to use exact dirty and writeback counters +in memcg oom reports. But that is saved for later. + +Link: http://lkml.kernel.org/r/20190329174609.164344-1-gthelen@google.com +Signed-off-by: Greg Thelen +Reviewed-by: Roman Gushchin +Acked-by: Johannes Weiner +Cc: Michal Hocko +Cc: Vladimir Davydov +Cc: Tejun Heo +Cc: [4.16+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/memcontrol.h | 5 ++++- + mm/memcontrol.c | 20 ++++++++++++++++++-- + 2 files changed, 22 insertions(+), 3 deletions(-) + +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -561,7 +561,10 @@ struct mem_cgroup *lock_page_memcg(struc + void __unlock_page_memcg(struct mem_cgroup *memcg); + void unlock_page_memcg(struct page *page); + +-/* idx can be of type enum memcg_stat_item or node_stat_item */ ++/* ++ * idx can be of type enum memcg_stat_item or node_stat_item. ++ * Keep in sync with memcg_exact_page_state(). ++ */ + static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, + int idx) + { +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -3882,6 +3882,22 @@ struct wb_domain *mem_cgroup_wb_domain(s + return &memcg->cgwb_domain; + } + ++/* ++ * idx can be of type enum memcg_stat_item or node_stat_item. ++ * Keep in sync with memcg_exact_page(). ++ */ ++static unsigned long memcg_exact_page_state(struct mem_cgroup *memcg, int idx) ++{ ++ long x = atomic_long_read(&memcg->stat[idx]); ++ int cpu; ++ ++ for_each_online_cpu(cpu) ++ x += per_cpu_ptr(memcg->stat_cpu, cpu)->count[idx]; ++ if (x < 0) ++ x = 0; ++ return x; ++} ++ + /** + * mem_cgroup_wb_stats - retrieve writeback related stats from its memcg + * @wb: bdi_writeback in question +@@ -3907,10 +3923,10 @@ void mem_cgroup_wb_stats(struct bdi_writ + struct mem_cgroup *memcg = mem_cgroup_from_css(wb->memcg_css); + struct mem_cgroup *parent; + +- *pdirty = memcg_page_state(memcg, NR_FILE_DIRTY); ++ *pdirty = memcg_exact_page_state(memcg, NR_FILE_DIRTY); + + /* this should eventually include NR_UNSTABLE_NFS */ +- *pwriteback = memcg_page_state(memcg, NR_WRITEBACK); ++ *pwriteback = memcg_exact_page_state(memcg, NR_WRITEBACK); + *pfilepages = mem_cgroup_nr_lru_pages(memcg, (1 << LRU_INACTIVE_FILE) | + (1 << LRU_ACTIVE_FILE)); + *pheadroom = PAGE_COUNTER_MAX; diff --git a/queue-5.0/series b/queue-5.0/series index 987323304d5..8bc8e4fca37 100644 --- a/queue-5.0/series +++ b/queue-5.0/series @@ -68,3 +68,6 @@ drm-sun4i-dw-hdmi-lower-max.-supported-rate-for-h6.patch drm-udl-add-a-release-method-and-delay-modeset-teardown.patch kvm-svm-fix-potential-get_num_contig_pages-overflow.patch include-linux-bitrev.h-fix-constant-bitrev.patch +mm-writeback-use-exact-memcg-dirty-counts.patch +asoc-intel-fix-crash-at-suspend-resume-after-failed-codec-registration.patch +asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch