From 9b53a13422162feac7c7ee58e5bc0e0a80a41963 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 20 Jun 2023 13:01:59 -0400 Subject: counter: Fix menuconfig "Counter support" submenu entries disappearance The current placement of the I8254 Kconfig entry results in the disappearance of the "Counter support" submenu items in menuconfig. Move the I8254 above the menuconfig COUNTER entry to restore the intended submenu behavior. Fixes: d428487471ba ("counter: i8254: Introduce the Intel 8254 interface library module") Reported-by: Jarkko Nikula Closes: https://lore.kernel.org/all/32ddaa7b-53a8-d61f-d526-b545bd561337@linux.intel.com/ Reviewed-by: Randy Dunlap Tested-by: Jarkko Nikula Reviewed-by: Jarkko Nikula Link: https://lore.kernel.org/r/20230620170159.556788-1-william.gray@linaro.org/ Signed-off-by: William Breathitt Gray --- drivers/counter/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index a61a4b9b8ec6..86536c2cc531 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -3,13 +3,6 @@ # Counter devices # -menuconfig COUNTER - tristate "Counter support" - help - This enables counter device support through the Generic Counter - interface. You only need to enable this, if you also want to enable - one or more of the counter device drivers below. - config I8254 tristate select COUNTER @@ -25,6 +18,13 @@ config I8254 If built as a module its name will be i8254. +menuconfig COUNTER + tristate "Counter support" + help + This enables counter device support through the Generic Counter + interface. You only need to enable this, if you also want to enable + one or more of the counter device drivers below. + if COUNTER config 104_QUAD_8 -- cgit v1.2.3 From a6fe043880820981f6e4918240f967ea79bb063e Mon Sep 17 00:00:00 2001 From: Kameron Carr Date: Fri, 23 Jun 2023 15:09:49 -0700 Subject: Drivers: hv: Change hv_free_hyperv_page() to take void * argument Currently hv_free_hyperv_page() takes an unsigned long argument, which is inconsistent with the void * return value from the corresponding hv_alloc_hyperv_page() function and variants. This creates unnecessary extra casting. Change the hv_free_hyperv_page() argument type to void *. Also remove redundant casts from invocations of hv_alloc_hyperv_page() and variants. Signed-off-by: Kameron Carr Reviewed-by: Nuno Das Neves Reviewed-by: Dexuan Cui Link: https://lore.kernel.org/r/1687558189-19734-1-git-send-email-kameroncarr@linux.microsoft.com Signed-off-by: Wei Liu --- drivers/hv/connection.c | 13 ++++++------- drivers/hv/hv_common.c | 10 +++++----- include/asm-generic/mshyperv.h | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 5978e9dbc286..ebf15f31d97e 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -209,8 +209,7 @@ int vmbus_connect(void) * Setup the vmbus event connection for channel interrupt * abstraction stuff */ - vmbus_connection.int_page = - (void *)hv_alloc_hyperv_zeroed_page(); + vmbus_connection.int_page = hv_alloc_hyperv_zeroed_page(); if (vmbus_connection.int_page == NULL) { ret = -ENOMEM; goto cleanup; @@ -225,8 +224,8 @@ int vmbus_connect(void) * Setup the monitor notification facility. The 1st page for * parent->child and the 2nd page for child->parent */ - vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_page(); - vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_page(); + vmbus_connection.monitor_pages[0] = hv_alloc_hyperv_page(); + vmbus_connection.monitor_pages[1] = hv_alloc_hyperv_page(); if ((vmbus_connection.monitor_pages[0] == NULL) || (vmbus_connection.monitor_pages[1] == NULL)) { ret = -ENOMEM; @@ -333,15 +332,15 @@ void vmbus_disconnect(void) destroy_workqueue(vmbus_connection.work_queue); if (vmbus_connection.int_page) { - hv_free_hyperv_page((unsigned long)vmbus_connection.int_page); + hv_free_hyperv_page(vmbus_connection.int_page); vmbus_connection.int_page = NULL; } set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[0], 1); set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[1], 1); - hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); - hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); + hv_free_hyperv_page(vmbus_connection.monitor_pages[0]); + hv_free_hyperv_page(vmbus_connection.monitor_pages[1]); vmbus_connection.monitor_pages[0] = NULL; vmbus_connection.monitor_pages[1] = NULL; } diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 542a1d53b303..6a2258fef1fe 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -115,12 +115,12 @@ void *hv_alloc_hyperv_zeroed_page(void) } EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page); -void hv_free_hyperv_page(unsigned long addr) +void hv_free_hyperv_page(void *addr) { if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - free_page(addr); + free_page((unsigned long)addr); else - kfree((void *)addr); + kfree(addr); } EXPORT_SYMBOL_GPL(hv_free_hyperv_page); @@ -253,7 +253,7 @@ static void hv_kmsg_dump_unregister(void) atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_report_block); - hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_free_hyperv_page(hv_panic_page); hv_panic_page = NULL; } @@ -270,7 +270,7 @@ static void hv_kmsg_dump_register(void) ret = kmsg_dump_register(&hv_kmsg_dumper); if (ret) { pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); - hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_free_hyperv_page(hv_panic_page); hv_panic_page = NULL; } } diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index 402a8c1c202d..a8f4b653ef4e 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -190,7 +190,7 @@ int hv_common_cpu_die(unsigned int cpu); void *hv_alloc_hyperv_page(void); void *hv_alloc_hyperv_zeroed_page(void); -void hv_free_hyperv_page(unsigned long addr); +void hv_free_hyperv_page(void *addr); /** * hv_cpu_number_to_vp_number() - Map CPU to VP. -- cgit v1.2.3 From 55e544e1a922d272b62ec576a3de92329f838ce9 Mon Sep 17 00:00:00 2001 From: Nischala Yelchuri Date: Tue, 20 Jun 2023 11:40:38 -0700 Subject: x86/hyperv: Improve code for referencing hyperv_pcpu_input_arg Several places in code for Hyper-V reference the per-CPU variable hyperv_pcpu_input_arg. Older code uses a multi-line sequence to reference the variable, and usually includes a cast. Newer code does a much simpler direct assignment. The latter is preferable as the complexity of the older code is unnecessary. Update older code to use the simpler direct assignment. Signed-off-by: Nischala Yelchuri Link: https://lore.kernel.org/r/1687286438-9421-1-git-send-email-niyelchu@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/hv_apic.c | 4 +--- arch/x86/hyperv/ivm.c | 7 +++---- arch/x86/hyperv/mmu.c | 12 ++---------- arch/x86/hyperv/nested.c | 11 ++--------- drivers/hv/hv_balloon.c | 2 +- 5 files changed, 9 insertions(+), 27 deletions(-) diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index 1fbda2f94184..b21335e6a210 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -107,7 +107,6 @@ static bool cpu_is_self(int cpu) static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, bool exclude_self) { - struct hv_send_ipi_ex **arg; struct hv_send_ipi_ex *ipi_arg; unsigned long flags; int nr_bank = 0; @@ -117,9 +116,8 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, return false; local_irq_save(flags); - arg = (struct hv_send_ipi_ex **)this_cpu_ptr(hyperv_pcpu_input_arg); + ipi_arg = *this_cpu_ptr(hyperv_pcpu_input_arg); - ipi_arg = *arg; if (unlikely(!ipi_arg)) goto ipi_mask_ex_done; diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index cc92388b7a99..9b63151bc6cd 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(hv_ghcb_msr_read); static int hv_mark_gpa_visibility(u16 count, const u64 pfn[], enum hv_mem_host_visibility visibility) { - struct hv_gpa_range_for_visibility **input_pcpu, *input; + struct hv_gpa_range_for_visibility *input; u16 pages_processed; u64 hv_status; unsigned long flags; @@ -262,9 +262,8 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[], } local_irq_save(flags); - input_pcpu = (struct hv_gpa_range_for_visibility **) - this_cpu_ptr(hyperv_pcpu_input_arg); - input = *input_pcpu; + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + if (unlikely(!input)) { local_irq_restore(flags); return -EINVAL; diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index 8460bd35e10c..1cc113200ff5 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -61,7 +61,6 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, const struct flush_tlb_info *info) { int cpu, vcpu, gva_n, max_gvas; - struct hv_tlb_flush **flush_pcpu; struct hv_tlb_flush *flush; u64 status; unsigned long flags; @@ -74,10 +73,7 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, local_irq_save(flags); - flush_pcpu = (struct hv_tlb_flush **) - this_cpu_ptr(hyperv_pcpu_input_arg); - - flush = *flush_pcpu; + flush = *this_cpu_ptr(hyperv_pcpu_input_arg); if (unlikely(!flush)) { local_irq_restore(flags); @@ -178,17 +174,13 @@ static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus, const struct flush_tlb_info *info) { int nr_bank = 0, max_gvas, gva_n; - struct hv_tlb_flush_ex **flush_pcpu; struct hv_tlb_flush_ex *flush; u64 status; if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) return HV_STATUS_INVALID_PARAMETER; - flush_pcpu = (struct hv_tlb_flush_ex **) - this_cpu_ptr(hyperv_pcpu_input_arg); - - flush = *flush_pcpu; + flush = *this_cpu_ptr(hyperv_pcpu_input_arg); if (info->mm) { /* diff --git a/arch/x86/hyperv/nested.c b/arch/x86/hyperv/nested.c index 5d70968c8538..9dc259fa322e 100644 --- a/arch/x86/hyperv/nested.c +++ b/arch/x86/hyperv/nested.c @@ -19,7 +19,6 @@ int hyperv_flush_guest_mapping(u64 as) { - struct hv_guest_mapping_flush **flush_pcpu; struct hv_guest_mapping_flush *flush; u64 status; unsigned long flags; @@ -30,10 +29,7 @@ int hyperv_flush_guest_mapping(u64 as) local_irq_save(flags); - flush_pcpu = (struct hv_guest_mapping_flush **) - this_cpu_ptr(hyperv_pcpu_input_arg); - - flush = *flush_pcpu; + flush = *this_cpu_ptr(hyperv_pcpu_input_arg); if (unlikely(!flush)) { local_irq_restore(flags); @@ -90,7 +86,6 @@ EXPORT_SYMBOL_GPL(hyperv_fill_flush_guest_mapping_list); int hyperv_flush_guest_mapping_range(u64 as, hyperv_fill_flush_list_func fill_flush_list_func, void *data) { - struct hv_guest_mapping_flush_list **flush_pcpu; struct hv_guest_mapping_flush_list *flush; u64 status; unsigned long flags; @@ -102,10 +97,8 @@ int hyperv_flush_guest_mapping_range(u64 as, local_irq_save(flags); - flush_pcpu = (struct hv_guest_mapping_flush_list **) - this_cpu_ptr(hyperv_pcpu_input_arg); + flush = *this_cpu_ptr(hyperv_pcpu_input_arg); - flush = *flush_pcpu; if (unlikely(!flush)) { local_irq_restore(flags); goto fault; diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index dffcc894f117..0d7a3ba66396 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1628,7 +1628,7 @@ static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info, WARN_ON_ONCE(nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES); WARN_ON_ONCE(sgl->length < (HV_HYP_PAGE_SIZE << page_reporting_order)); local_irq_save(flags); - hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg); + hint = *this_cpu_ptr(hyperv_pcpu_input_arg); if (!hint) { local_irq_restore(flags); return -ENOSPC; -- cgit v1.2.3 From d1478aea649e739a0a0e4890cd8b049ae5d08c13 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 29 Jun 2023 18:01:32 +0200 Subject: memory: tegra: Add dummy implementation on Tegra194 With the introduction of commit 9365bf006f53 ("PCI: tegra194: Add interconnect support in Tegra234"), the PCI driver on Tegra194 and later requires an interconnect provider. However, a provider is currently only exposed on Tegra234 and this causes PCI on Tegra194 to defer probe indefinitely. Fix this by adding a dummy implementation on Tegra194. This allows nodes to be provided to interconnect consumers, but doesn't do any bandwidth accounting or frequency scaling. Fixes: 9365bf006f53 ("PCI: tegra194: Add interconnect support in Tegra234") Reported-by: Jon Hunter Signed-off-by: Thierry Reding Reviewed-by: Sumit Gupta Tested-by: Sumit Gupta Link: https://lore.kernel.org/r/20230629160132.768940-1-thierry.reding@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/mc.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/memory/tegra/tegra194.c | 1 + drivers/memory/tegra/tegra234.c | 23 +---------------------- include/soc/tegra/mc.h | 3 +++ 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 4a750da1c12a..deb6e65b59af 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -755,6 +755,43 @@ const char *const tegra_mc_error_names[8] = { [6] = "SMMU translation error", }; +struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data) +{ + struct tegra_mc *mc = icc_provider_to_tegra_mc(data); + struct icc_node *node; + + list_for_each_entry(node, &mc->provider.nodes, node_list) { + if (node->id == spec->args[0]) + return node; + } + + /* + * If a client driver calls devm_of_icc_get() before the MC driver + * is probed, then return EPROBE_DEFER to the client driver. + */ + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra_mc_icc_get(struct icc_node *node, u32 *average, u32 *peak) +{ + *average = 0; + *peak = 0; + + return 0; +} + +static int tegra_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + return 0; +} + +const struct tegra_mc_icc_ops tegra_mc_icc_ops = { + .xlate = tegra_mc_icc_xlate, + .aggregate = icc_std_aggregate, + .get_bw = tegra_mc_icc_get, + .set = tegra_mc_icc_set, +}; + /* * Memory Controller (MC) has few Memory Clients that are issuing memory * bandwidth allocation requests to the MC interconnect provider. The MC diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c index b2416ee3ac26..26035ac3a1eb 100644 --- a/drivers/memory/tegra/tegra194.c +++ b/drivers/memory/tegra/tegra194.c @@ -1355,6 +1355,7 @@ const struct tegra_mc_soc tegra194_mc_soc = { MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, .has_addr_hi_reg = true, .ops = &tegra186_mc_ops, + .icc_ops = &tegra_mc_icc_ops, .ch_intmask = 0x00000f00, .global_intstatus_channel_shift = 8, }; diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c index 8e873a7bc34f..4469430aa5fb 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -889,27 +889,6 @@ static int tegra234_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, return 0; } -static struct icc_node* -tegra234_mc_of_icc_xlate(struct of_phandle_args *spec, void *data) -{ - struct tegra_mc *mc = icc_provider_to_tegra_mc(data); - unsigned int cl_id = spec->args[0]; - struct icc_node *node; - - list_for_each_entry(node, &mc->provider.nodes, node_list) { - if (node->id != cl_id) - continue; - - return node; - } - - /* - * If a client driver calls devm_of_icc_get() before the MC driver - * is probed, then return EPROBE_DEFER to the client driver. - */ - return ERR_PTR(-EPROBE_DEFER); -} - static int tegra234_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak) { *avg = 0; @@ -919,7 +898,7 @@ static int tegra234_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pea } static const struct tegra_mc_icc_ops tegra234_mc_icc_ops = { - .xlate = tegra234_mc_of_icc_xlate, + .xlate = tegra_mc_icc_xlate, .aggregate = tegra234_mc_icc_aggregate, .get_bw = tegra234_mc_icc_get_init_bw, .set = tegra234_mc_icc_set, diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index fc3001483e62..a5ef84944a06 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -175,6 +175,9 @@ struct tegra_mc_icc_ops { int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak); }; +struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data); +extern const struct tegra_mc_icc_ops tegra_mc_icc_ops; + struct tegra_mc_ops { /* * @probe: Callback to set up SoC-specific bits of the memory controller. This is called -- cgit v1.2.3 From 6e2acbfe59b83043bc7ae1bb39fac4fc9dcd5a18 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Wed, 5 Jul 2023 00:54:04 +0300 Subject: clk: meson: change usleep_range() to udelay() for atomic context The function meson_clk_pll_enable() can be invoked under the enable_lock spinlock from the clk core logic, which risks a kernel panic during the usleep_range() call: BUG: scheduling while atomic: kworker/u4:2/36/0x00000002 Modules linked in: g_ffs usb_f_fs libcomposite CPU: 1 PID: 36 Comm: kworker/u4:2 Not tainted 6.4.0-rc5 #273 Workqueue: events_unbound async_run_entry_fn Call trace: dump_backtrace+0x9c/0x128 show_stack+0x20/0x38 dump_stack_lvl+0x48/0x60 dump_stack+0x18/0x28 __schedule_bug+0x58/0x78 __schedule+0x828/0xa88 schedule+0x64/0xd8 schedule_hrtimeout_range_clock+0xd0/0x208 schedule_hrtimeout_range+0x1c/0x30 usleep_range_state+0x6c/0xa8 meson_clk_pll_enable+0x1f4/0x310 clk_core_enable+0x78/0x200 clk_core_enable+0x58/0x200 clk_core_enable+0x58/0x200 clk_core_enable+0x58/0x200 clk_enable+0x34/0x60 So it is required to use the udelay() function instead of usleep_range() for the atomic context safety. Fixes: b6ec400aa153 ("clk: meson: introduce new pll power-on sequence for A1 SoC family") Reported-by: Jan Dakinevich Signed-off-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20230704215404.11533-1-ddrokosov@sberdevices.ru Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 8fef90bf962f..6fa7639a3050 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -367,9 +367,9 @@ static int meson_clk_pll_enable(struct clk_hw *hw) * 3. enable the lock detect module */ if (MESON_PARM_APPLICABLE(&pll->current_en)) { - usleep_range(10, 20); + udelay(10); meson_parm_write(clk->map, &pll->current_en, 1); - usleep_range(40, 50); + udelay(40); } if (MESON_PARM_APPLICABLE(&pll->l_detect)) { -- cgit v1.2.3 From daf60d6cca26e50d65dac374db92e58de745ad26 Mon Sep 17 00:00:00 2001 From: gaoming Date: Wed, 5 Jul 2023 15:15:15 +0800 Subject: exfat: use kvmalloc_array/kvfree instead of kmalloc_array/kfree The call stack shown below is a scenario in the Linux 4.19 kernel. Allocating memory failed where exfat fs use kmalloc_array due to system memory fragmentation, while the u-disk was inserted without recognition. Devices such as u-disk using the exfat file system are pluggable and may be insert into the system at any time. However, long-term running systems cannot guarantee the continuity of physical memory. Therefore, it's necessary to address this issue. Binder:2632_6: page allocation failure: order:4, mode:0x6040c0(GFP_KERNEL|__GFP_COMP), nodemask=(null) Call trace: [242178.097582] dump_backtrace+0x0/0x4 [242178.097589] dump_stack+0xf4/0x134 [242178.097598] warn_alloc+0xd8/0x144 [242178.097603] __alloc_pages_nodemask+0x1364/0x1384 [242178.097608] kmalloc_order+0x2c/0x510 [242178.097612] kmalloc_order_trace+0x40/0x16c [242178.097618] __kmalloc+0x360/0x408 [242178.097624] load_alloc_bitmap+0x160/0x284 [242178.097628] exfat_fill_super+0xa3c/0xe7c [242178.097635] mount_bdev+0x2e8/0x3a0 [242178.097638] exfat_fs_mount+0x40/0x50 [242178.097643] mount_fs+0x138/0x2e8 [242178.097649] vfs_kern_mount+0x90/0x270 [242178.097655] do_mount+0x798/0x173c [242178.097659] ksys_mount+0x114/0x1ac [242178.097665] __arm64_sys_mount+0x24/0x34 [242178.097671] el0_svc_common+0xb8/0x1b8 [242178.097676] el0_svc_handler+0x74/0x90 [242178.097681] el0_svc+0x8/0x340 By analyzing the exfat code,we found that continuous physical memory is not required here,so kvmalloc_array is used can solve this problem. Cc: stable@vger.kernel.org Signed-off-by: gaoming Signed-off-by: Namjae Jeon --- fs/exfat/balloc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index 9f42f25fab92..e918decb3735 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -69,7 +69,7 @@ static int exfat_allocate_bitmap(struct super_block *sb, } sbi->map_sectors = ((need_map_size - 1) >> (sb->s_blocksize_bits)) + 1; - sbi->vol_amap = kmalloc_array(sbi->map_sectors, + sbi->vol_amap = kvmalloc_array(sbi->map_sectors, sizeof(struct buffer_head *), GFP_KERNEL); if (!sbi->vol_amap) return -ENOMEM; @@ -84,7 +84,7 @@ static int exfat_allocate_bitmap(struct super_block *sb, while (j < i) brelse(sbi->vol_amap[j++]); - kfree(sbi->vol_amap); + kvfree(sbi->vol_amap); sbi->vol_amap = NULL; return -EIO; } @@ -138,7 +138,7 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi) for (i = 0; i < sbi->map_sectors; i++) __brelse(sbi->vol_amap[i]); - kfree(sbi->vol_amap); + kvfree(sbi->vol_amap); } int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync) -- cgit v1.2.3 From d8630f050d3fd2079f8617dd6c00c6509109c755 Mon Sep 17 00:00:00 2001 From: Mike Tipton Date: Fri, 23 Jun 2023 14:50:42 +0200 Subject: interconnect: qcom: Add support for mask-based BCMs Some BCMs aren't directly associated with the data path (i.e. ACV) and therefore don't communicate using BW. Instead, they are simply enabled/disabled with a simple bit mask. Add support for these. Origin commit retrieved from: https://git.codelinaro.org/clo/la/kernel/msm-5.15/-/commit/2d1573e0206998151b342e6b52a4c0f7234d7e36 Signed-off-by: Mike Tipton [narmstrong: removed copyright change from original commit] Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230619-topic-sm8550-upstream-interconnect-mask-vote-v2-1-709474b151cc@linaro.org Fixes: fafc114a468e ("interconnect: qcom: Add SM8450 interconnect provider driver") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/bcm-voter.c | 5 +++++ drivers/interconnect/qcom/icc-rpmh.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c index 8f385f9c2dd3..d5f2a6b5376b 100644 --- a/drivers/interconnect/qcom/bcm-voter.c +++ b/drivers/interconnect/qcom/bcm-voter.c @@ -83,6 +83,11 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm) temp = agg_peak[bucket] * bcm->vote_scale; bcm->vote_y[bucket] = bcm_div(temp, bcm->aux_data.unit); + + if (bcm->enable_mask && (bcm->vote_x[bucket] || bcm->vote_y[bucket])) { + bcm->vote_x[bucket] = 0; + bcm->vote_y[bucket] = bcm->enable_mask; + } } if (bcm->keepalive && bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 && diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 04391c1ba465..7843d8864d6b 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -81,6 +81,7 @@ struct qcom_icc_node { * @vote_x: aggregated threshold values, represents sum_bw when @type is bw bcm * @vote_y: aggregated threshold values, represents peak_bw when @type is bw bcm * @vote_scale: scaling factor for vote_x and vote_y + * @enable_mask: optional mask to send as vote instead of vote_x/vote_y * @dirty: flag used to indicate whether the bcm needs to be committed * @keepalive: flag used to indicate whether a keepalive is required * @aux_data: auxiliary data used when calculating threshold values and @@ -97,6 +98,7 @@ struct qcom_icc_bcm { u64 vote_x[QCOM_ICC_NUM_BUCKETS]; u64 vote_y[QCOM_ICC_NUM_BUCKETS]; u64 vote_scale; + u32 enable_mask; bool dirty; bool keepalive; struct bcm_db aux_data; -- cgit v1.2.3 From be02db24cf840bc0fdfbecc78ad803619dd143e6 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 23 Jun 2023 14:50:43 +0200 Subject: interconnect: qcom: sm8450: add enable_mask for bcm nodes Set the proper enable_mask to nodes requiring such value to be used instead of a bandwidth when voting. The masks were copied from the downstream implementation at [1]. [1] https://git.codelinaro.org/clo/la/kernel/msm-5.10/-/blob/KERNEL.PLATFORM.1.0.r2-05600-WAIPIOLE.0/drivers/interconnect/qcom/waipio.c Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230619-topic-sm8550-upstream-interconnect-mask-vote-v2-2-709474b151cc@linaro.org Fixes: fafc114a468e ("interconnect: qcom: Add SM8450 interconnect provider driver") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8450.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c index 2d7a8e7b85ec..e64c214b4020 100644 --- a/drivers/interconnect/qcom/sm8450.c +++ b/drivers/interconnect/qcom/sm8450.c @@ -1337,6 +1337,7 @@ static struct qcom_icc_node qns_mem_noc_sf_disp = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = 0x8, .num_nodes = 1, .nodes = { &ebi }, }; @@ -1349,6 +1350,7 @@ static struct qcom_icc_bcm bcm_ce0 = { static struct qcom_icc_bcm bcm_cn0 = { .name = "CN0", + .enable_mask = 0x1, .keepalive = true, .num_nodes = 55, .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie, @@ -1383,6 +1385,7 @@ static struct qcom_icc_bcm bcm_cn0 = { static struct qcom_icc_bcm bcm_co0 = { .name = "CO0", + .enable_mask = 0x1, .num_nodes = 2, .nodes = { &qxm_nsp, &qns_nsp_gemnoc }, }; @@ -1403,6 +1406,7 @@ static struct qcom_icc_bcm bcm_mm0 = { static struct qcom_icc_bcm bcm_mm1 = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 12, .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp, &qnm_camnoc_sf, &qnm_mdp, @@ -1445,6 +1449,7 @@ static struct qcom_icc_bcm bcm_sh0 = { static struct qcom_icc_bcm bcm_sh1 = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 7, .nodes = { &alm_gpu_tcu, &alm_sys_tcu, &qnm_nsp_gemnoc, &qnm_pcie, @@ -1461,6 +1466,7 @@ static struct qcom_icc_bcm bcm_sn0 = { static struct qcom_icc_bcm bcm_sn1 = { .name = "SN1", + .enable_mask = 0x1, .num_nodes = 4, .nodes = { &qhm_gic, &qxm_pimem, &xm_gic, &qns_gemnoc_gc }, @@ -1492,6 +1498,7 @@ static struct qcom_icc_bcm bcm_sn7 = { static struct qcom_icc_bcm bcm_acv_disp = { .name = "ACV", + .enable_mask = 0x1, .num_nodes = 1, .nodes = { &ebi_disp }, }; @@ -1510,6 +1517,7 @@ static struct qcom_icc_bcm bcm_mm0_disp = { static struct qcom_icc_bcm bcm_mm1_disp = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 3, .nodes = { &qnm_mdp_disp, &qnm_rot_disp, &qns_mem_noc_sf_disp }, @@ -1523,6 +1531,7 @@ static struct qcom_icc_bcm bcm_sh0_disp = { static struct qcom_icc_bcm bcm_sh1_disp = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 1, .nodes = { &qnm_pcie_disp }, }; -- cgit v1.2.3 From 0dc82bd9e4627065dbc6ac8468296aa18f13c840 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 23 Jun 2023 14:50:44 +0200 Subject: interconnect: qcom: sm8550: add enable_mask for bcm nodes Set the proper enable_mask to nodes requiring such value to be used instead of a bandwidth when voting. The masks were copied from the downstream implementation at [1]. [1] https://git.codelinaro.org/clo/la/kernel/msm-5.15/-/blob/kernel.lnx.5.15.r1-rel/drivers/interconnect/qcom/kalama.c Reviewed-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20230619-topic-sm8550-upstream-interconnect-mask-vote-v2-3-709474b151cc@linaro.org Fixes: e6f0d6a30f73 ("interconnect: qcom: Add SM8550 interconnect provider driver") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8550.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c index d823ba988ef6..0864ed285375 100644 --- a/drivers/interconnect/qcom/sm8550.c +++ b/drivers/interconnect/qcom/sm8550.c @@ -1473,6 +1473,7 @@ static struct qcom_icc_node qns_mem_noc_sf_cam_ife_2 = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = 0x8, .num_nodes = 1, .nodes = { &ebi }, }; @@ -1485,6 +1486,7 @@ static struct qcom_icc_bcm bcm_ce0 = { static struct qcom_icc_bcm bcm_cn0 = { .name = "CN0", + .enable_mask = 0x1, .keepalive = true, .num_nodes = 54, .nodes = { &qsm_cfg, &qhs_ahb2phy0, @@ -1524,6 +1526,7 @@ static struct qcom_icc_bcm bcm_cn1 = { static struct qcom_icc_bcm bcm_co0 = { .name = "CO0", + .enable_mask = 0x1, .num_nodes = 2, .nodes = { &qxm_nsp, &qns_nsp_gemnoc }, }; @@ -1549,6 +1552,7 @@ static struct qcom_icc_bcm bcm_mm0 = { static struct qcom_icc_bcm bcm_mm1 = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 8, .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp, &qnm_camnoc_sf, &qnm_vapss_hcp, @@ -1589,6 +1593,7 @@ static struct qcom_icc_bcm bcm_sh0 = { static struct qcom_icc_bcm bcm_sh1 = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 13, .nodes = { &alm_gpu_tcu, &alm_sys_tcu, &chm_apps, &qnm_gpu, @@ -1608,6 +1613,7 @@ static struct qcom_icc_bcm bcm_sn0 = { static struct qcom_icc_bcm bcm_sn1 = { .name = "SN1", + .enable_mask = 0x1, .num_nodes = 3, .nodes = { &qhm_gic, &xm_gic, &qns_gemnoc_gc }, @@ -1633,6 +1639,7 @@ static struct qcom_icc_bcm bcm_sn7 = { static struct qcom_icc_bcm bcm_acv_disp = { .name = "ACV", + .enable_mask = 0x1, .num_nodes = 1, .nodes = { &ebi_disp }, }; @@ -1657,12 +1664,14 @@ static struct qcom_icc_bcm bcm_sh0_disp = { static struct qcom_icc_bcm bcm_sh1_disp = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 2, .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp }, }; static struct qcom_icc_bcm bcm_acv_cam_ife_0 = { .name = "ACV", + .enable_mask = 0x0, .num_nodes = 1, .nodes = { &ebi_cam_ife_0 }, }; @@ -1681,6 +1690,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_0 = { static struct qcom_icc_bcm bcm_mm1_cam_ife_0 = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 4, .nodes = { &qnm_camnoc_hf_cam_ife_0, &qnm_camnoc_icp_cam_ife_0, &qnm_camnoc_sf_cam_ife_0, &qns_mem_noc_sf_cam_ife_0 }, @@ -1694,6 +1704,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_0 = { static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 3, .nodes = { &qnm_mnoc_hf_cam_ife_0, &qnm_mnoc_sf_cam_ife_0, &qnm_pcie_cam_ife_0 }, @@ -1701,6 +1712,7 @@ static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = { static struct qcom_icc_bcm bcm_acv_cam_ife_1 = { .name = "ACV", + .enable_mask = 0x0, .num_nodes = 1, .nodes = { &ebi_cam_ife_1 }, }; @@ -1719,6 +1731,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_1 = { static struct qcom_icc_bcm bcm_mm1_cam_ife_1 = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 4, .nodes = { &qnm_camnoc_hf_cam_ife_1, &qnm_camnoc_icp_cam_ife_1, &qnm_camnoc_sf_cam_ife_1, &qns_mem_noc_sf_cam_ife_1 }, @@ -1732,6 +1745,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_1 = { static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 3, .nodes = { &qnm_mnoc_hf_cam_ife_1, &qnm_mnoc_sf_cam_ife_1, &qnm_pcie_cam_ife_1 }, @@ -1739,6 +1753,7 @@ static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = { static struct qcom_icc_bcm bcm_acv_cam_ife_2 = { .name = "ACV", + .enable_mask = 0x0, .num_nodes = 1, .nodes = { &ebi_cam_ife_2 }, }; @@ -1757,6 +1772,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_2 = { static struct qcom_icc_bcm bcm_mm1_cam_ife_2 = { .name = "MM1", + .enable_mask = 0x1, .num_nodes = 4, .nodes = { &qnm_camnoc_hf_cam_ife_2, &qnm_camnoc_icp_cam_ife_2, &qnm_camnoc_sf_cam_ife_2, &qns_mem_noc_sf_cam_ife_2 }, @@ -1770,6 +1786,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_2 = { static struct qcom_icc_bcm bcm_sh1_cam_ife_2 = { .name = "SH1", + .enable_mask = 0x1, .num_nodes = 3, .nodes = { &qnm_mnoc_hf_cam_ife_2, &qnm_mnoc_sf_cam_ife_2, &qnm_pcie_cam_ife_2 }, -- cgit v1.2.3 From 3cb11fe244d516f757c1022cfa971528d525fe65 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 23 Jun 2023 14:50:45 +0200 Subject: interconnect: qcom: sa8775p: add enable_mask for bcm nodes Set the proper enable_mask the ACV node requiring such value to be used instead of a bandwidth when voting. The masks was copied from the downstream implementation at [1]. [1] https://git.codelinaro.org/clo/la/kernel/msm-5.15/-/blob/kernel.lnx.5.15.r32-rel/drivers/interconnect/qcom/lemans.c Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230619-topic-sm8550-upstream-interconnect-mask-vote-v2-4-709474b151cc@linaro.org Fixes: 3655a63f9661 ("interconnect: qcom: add a driver for sa8775p") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sa8775p.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c index da21cc31a580..f56538669de0 100644 --- a/drivers/interconnect/qcom/sa8775p.c +++ b/drivers/interconnect/qcom/sa8775p.c @@ -1873,6 +1873,7 @@ static struct qcom_icc_node srvc_snoc = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = 0x8, .num_nodes = 1, .nodes = { &ebi }, }; -- cgit v1.2.3 From db66795f61354c373ecdadbdae1ed253a96c47cb Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Jul 2023 15:44:30 -0500 Subject: arm64: dts: stratix10: fix incorrect I2C property for SCL signal The correct dts property for the SCL falling time is "i2c-scl-falling-time-ns". Fixes: c8da1d15b8a4 ("arm64: dts: stratix10: i2c clock running out of spec") Cc: stable@vger.kernel.org Signed-off-by: Dinh Nguyen --- arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts | 2 +- arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts index 38ae674f2f02..3037f58057c9 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts @@ -145,7 +145,7 @@ status = "okay"; clock-frequency = <100000>; i2c-sda-falling-time-ns = <890>; /* hcnt */ - i2c-sdl-falling-time-ns = <890>; /* lcnt */ + i2c-scl-falling-time-ns = <890>; /* lcnt */ pinctrl-names = "default", "gpio"; pinctrl-0 = <&i2c1_pmx_func>; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts index ede99dcc0558..f4cf30bac557 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts @@ -141,7 +141,7 @@ status = "okay"; clock-frequency = <100000>; i2c-sda-falling-time-ns = <890>; /* hcnt */ - i2c-sdl-falling-time-ns = <890>; /* lcnt */ + i2c-scl-falling-time-ns = <890>; /* lcnt */ adc@14 { compatible = "lltc,ltc2497"; -- cgit v1.2.3 From b2ec116aad38aa9c8b67fad4314e50823adf6949 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Jul 2023 12:38:20 +0200 Subject: workqueue: Fix cpu_intensive_thresh_us name in help text There exists no parameter called "cpu_intensive_threshold_us". The actual parameter name is "cpu_intensive_thresh_us". Fixes: 6363845005202148 ("workqueue: Report work funcs that trigger automatic CPU_INTENSIVE mechanism") Signed-off-by: Geert Uytterhoeven Reviewed-by: Randy Dunlap Signed-off-by: Tejun Heo --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index fbc89baf7de6..d6798513a8c2 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1200,7 +1200,7 @@ config WQ_CPU_INTENSIVE_REPORT help Say Y here to enable reporting of concurrency-managed per-cpu work items that hog CPUs for longer than - workqueue.cpu_intensive_threshold_us. Workqueue automatically + workqueue.cpu_intensive_thresh_us. Workqueue automatically detects and excludes them from concurrency management to prevent them from stalling other per-cpu work items. Occassional triggering may not necessarily indicate a problem. Repeated -- cgit v1.2.3 From 8544cda94dae6be3f1359539079c68bb731428b1 Mon Sep 17 00:00:00 2001 From: Olivier Maignial Date: Fri, 23 Jun 2023 17:33:36 +0200 Subject: mtd: spinand: toshiba: Fix ecc_get_status Reading ECC status is failing. tx58cxgxsxraix_ecc_get_status() is using on-stack buffer for SPINAND_GET_FEATURE_OP() output. It is not suitable for DMA needs of spi-mem. Fix this by using the spi-mem operations dedicated buffer spinand->scratchbuf. See spinand->scratchbuf: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/mtd/spinand.h?h=v6.3#n418 spi_mem_check_op(): https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spi-mem.c?h=v6.3#n199 Fixes: 10949af1681d ("mtd: spinand: Add initial support for Toshiba TC58CVG2S0H") Cc: stable@vger.kernel.org Signed-off-by: Olivier Maignial Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/DB4P250MB1032553D05FBE36DEE0D311EFE23A@DB4P250MB1032.EURP250.PROD.OUTLOOK.COM --- drivers/mtd/nand/spi/toshiba.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index 7380b1ebaccd..a80427c13121 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -73,7 +73,7 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, { struct nand_device *nand = spinand_to_nand(spinand); u8 mbf = 0; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf); switch (status & STATUS_ECC_MASK) { case STATUS_ECC_NO_BITFLIPS: @@ -92,7 +92,7 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, if (spi_mem_exec_op(spinand->spimem, &op)) return nanddev_get_ecc_conf(nand)->strength; - mbf >>= 4; + mbf = *(spinand->scratchbuf) >> 4; if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) return nanddev_get_ecc_conf(nand)->strength; -- cgit v1.2.3 From f5a05060670a4d8d6523afc7963eb559c2e3615f Mon Sep 17 00:00:00 2001 From: Olivier Maignial Date: Fri, 23 Jun 2023 17:33:37 +0200 Subject: mtd: spinand: winbond: Fix ecc_get_status Reading ECC status is failing. w25n02kv_ecc_get_status() is using on-stack buffer for SPINAND_GET_FEATURE_OP() output. It is not suitable for DMA needs of spi-mem. Fix this by using the spi-mem operations dedicated buffer spinand->scratchbuf. See spinand->scratchbuf: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/mtd/spinand.h?h=v6.3#n418 spi_mem_check_op(): https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spi-mem.c?h=v6.3#n199 Fixes: 6154c7a58348 ("mtd: spinand: winbond: add Winbond W25N02KV flash support") Cc: stable@vger.kernel.org Signed-off-by: Olivier Maignial Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/DB4P250MB1032EDB9E36B764A33769039FE23A@DB4P250MB1032.EURP250.PROD.OUTLOOK.COM --- drivers/mtd/nand/spi/winbond.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 3ad58cd284d8..f507e3759301 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -108,7 +108,7 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, { struct nand_device *nand = spinand_to_nand(spinand); u8 mbf = 0; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf); switch (status & STATUS_ECC_MASK) { case STATUS_ECC_NO_BITFLIPS: @@ -126,7 +126,7 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, if (spi_mem_exec_op(spinand->spimem, &op)) return nanddev_get_ecc_conf(nand)->strength; - mbf >>= 4; + mbf = *(spinand->scratchbuf) >> 4; if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) return nanddev_get_ecc_conf(nand)->strength; -- cgit v1.2.3 From d8403b9eeee66d5dd81ecb9445800b108c267ce3 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Sun, 25 Jun 2023 00:10:21 +0530 Subject: mtd: rawnand: omap_elm: Fix incorrect type in assignment Once the ECC word endianness is converted to BE32, we force cast it to u32 so we can use elm_write_reg() which in turn uses writel(). Fixes below sparse warnings: drivers/mtd/nand/raw/omap_elm.c:180:37: sparse: expected unsigned int [usertype] val drivers/mtd/nand/raw/omap_elm.c:180:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:185:37: sparse: expected unsigned int [usertype] val drivers/mtd/nand/raw/omap_elm.c:185:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:190:37: sparse: expected unsigned int [usertype] val drivers/mtd/nand/raw/omap_elm.c:190:37: sparse: got restricted __be32 [usertype] >> drivers/mtd/nand/raw/omap_elm.c:200:40: sparse: sparse: restricted __be32 degrades to integer drivers/mtd/nand/raw/omap_elm.c:206:39: sparse: sparse: restricted __be32 degrades to integer drivers/mtd/nand/raw/omap_elm.c:210:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:210:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:213:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:213:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:216:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:216:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:219:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:219:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:222:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:222:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:225:37: sparse: expected unsigned int [assigned] [usertype] val drivers/mtd/nand/raw/omap_elm.c:225:37: sparse: got restricted __be32 [usertype] drivers/mtd/nand/raw/omap_elm.c:228:39: sparse: sparse: restricted __be32 degrades to integer Fixes: bf22433575ef ("mtd: devices: elm: Add support for ELM error correction") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306212211.WDXokuWh-lkp@intel.com/ Signed-off-by: Roger Quadros Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230624184021.7740-1-rogerq@kernel.org --- drivers/mtd/nand/raw/omap_elm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 6e1eac6644a6..4a97d4a76454 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -177,17 +177,17 @@ static void elm_load_syndrome(struct elm_info *info, switch (info->bch_type) { case BCH8_ECC: /* syndrome fragment 0 = ecc[9-12B] */ - val = cpu_to_be32(*(u32 *) &ecc[9]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[9]); elm_write_reg(info, offset, val); /* syndrome fragment 1 = ecc[5-8B] */ offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[5]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[5]); elm_write_reg(info, offset, val); /* syndrome fragment 2 = ecc[1-4B] */ offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[1]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[1]); elm_write_reg(info, offset, val); /* syndrome fragment 3 = ecc[0B] */ @@ -197,35 +197,35 @@ static void elm_load_syndrome(struct elm_info *info, break; case BCH4_ECC: /* syndrome fragment 0 = ecc[20-52b] bits */ - val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) | + val = ((__force u32)cpu_to_be32(*(u32 *)&ecc[3]) >> 4) | ((ecc[2] & 0xf) << 28); elm_write_reg(info, offset, val); /* syndrome fragment 1 = ecc[0-20b] bits */ offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12; + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 12; elm_write_reg(info, offset, val); break; case BCH16_ECC: - val = cpu_to_be32(*(u32 *) &ecc[22]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[22]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[18]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[18]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[14]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[14]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[10]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[10]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[6]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[6]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[2]); + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[2]); elm_write_reg(info, offset, val); offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16; + val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 16; elm_write_reg(info, offset, val); break; default: -- cgit v1.2.3 From 7e6b04f9238eab0f684fafd158c1f32ea65b9eaa Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Wed, 5 Jul 2023 09:52:10 +0300 Subject: mtd: rawnand: meson: fix OOB available bytes for ECC It is incorrect to calculate number of OOB bytes for ECC engine using some "already known" ECC step size (1024 bytes here). Number of such bytes for ECC engine must be whole OOB except 2 bytes for bad block marker, while proper ECC step size and strength will be selected by ECC logic. Fixes: 8fae856c5350 ("mtd: rawnand: meson: add support for Amlogic NAND flash controller") Cc: Signed-off-by: Arseniy Krasnov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230705065211.293500-1-AVKrasnov@sberdevices.ru --- drivers/mtd/nand/raw/meson_nand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index d3faf8086631..b10011dec1e6 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1278,7 +1278,6 @@ static int meson_nand_attach_chip(struct nand_chip *nand) struct meson_nfc *nfc = nand_get_controller_data(nand); struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); struct mtd_info *mtd = nand_to_mtd(nand); - int nsectors = mtd->writesize / 1024; int raw_writesize; int ret; @@ -1304,7 +1303,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand) nand->options |= NAND_NO_SUBPAGE_WRITE; ret = nand_ecc_choose_conf(nand, nfc->data->ecc_caps, - mtd->oobsize - 2 * nsectors); + mtd->oobsize - 2); if (ret) { dev_err(nfc->dev, "failed to ECC init\n"); return -EINVAL; -- cgit v1.2.3 From b1e213a9e31c20206f111ec664afcf31cbfe0dbb Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Fri, 7 Jul 2023 21:58:45 +0800 Subject: idmaengine: make FSL_EDMA and INTEL_IDMA64 depends on HAS_IOMEM On s390 systems (aka mainframes), it has classic channel devices for networking and permanent storage that are currently even more common than PCI devices. Hence it could have a fully functional s390 kernel with CONFIG_PCI=n, then the relevant iomem mapping functions [including ioremap(), devm_ioremap(), etc.] are not available. Here let FSL_EDMA and INTEL_IDMA64 depend on HAS_IOMEM so that it won't be built to cause below compiling error if PCI is unset. -------- ERROR: modpost: "devm_platform_ioremap_resource" [drivers/dma/fsl-edma.ko] undefined! ERROR: modpost: "devm_platform_ioremap_resource" [drivers/dma/idma64.ko] undefined! -------- Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306211329.ticOJCSv-lkp@intel.com/ Signed-off-by: Baoquan He Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Link: https://lore.kernel.org/r/20230707135852.24292-2-bhe@redhat.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 644c188d6a11..08fdd0e2ed1b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -211,6 +211,7 @@ config FSL_DMA config FSL_EDMA tristate "Freescale eDMA engine support" depends on OF + depends on HAS_IOMEM select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help @@ -280,6 +281,7 @@ config IMX_SDMA config INTEL_IDMA64 tristate "Intel integrated DMA 64-bit support" + depends on HAS_IOMEM select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help -- cgit v1.2.3 From a68b48afc050a9456ed4ed19d8755e0f925b44e6 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Wed, 5 Jul 2023 19:39:12 +0800 Subject: dmaengine: xilinx: xdma: Fix Judgment of the return value Fix: make IS_ERR() judge the devm_ioremap_resource() function return. Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Signed-off-by: Minjie Du Acked-by: Michal Simek Link: https://lore.kernel.org/r/20230705113912.16247-1-duminjie@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 93ee298d52b8..ad5ff63354cf 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -892,7 +892,7 @@ static int xdma_probe(struct platform_device *pdev) } reg_base = devm_ioremap_resource(&pdev->dev, res); - if (!reg_base) { + if (IS_ERR(reg_base)) { xdma_err(xdev, "ioremap failed"); goto failed; } -- cgit v1.2.3 From d44263222134b5635932974c6177a5cba65a07e8 Mon Sep 17 00:00:00 2001 From: Sergei Antonov Date: Tue, 27 Jun 2023 15:05:49 +0300 Subject: mmc: moxart: read scr register without changing byte order Conversion from big-endian to native is done in a common function mmc_app_send_scr(). Converting in moxart_transfer_pio() is extra. Double conversion on a LE system returns an incorrect SCR value, leads to errors: mmc0: unrecognised SCR structure version 8 Fixes: 1b66e94e6b99 ("mmc: moxart: Add MOXA ART SD/MMC driver") Signed-off-by: Sergei Antonov Cc: Jonas Jensen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230627120549.2400325-1-saproj@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 2d002c81dcf3..d0d6ffcf78d4 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -338,13 +338,7 @@ static void moxart_transfer_pio(struct moxart_host *host) return; } for (len = 0; len < remain && len < host->fifo_width;) { - /* SCR data must be read in big endian. */ - if (data->mrq->cmd->opcode == SD_APP_SEND_SCR) - *sgp = ioread32be(host->base + - REG_DATA_WINDOW); - else - *sgp = ioread32(host->base + - REG_DATA_WINDOW); + *sgp = ioread32(host->base + REG_DATA_WINDOW); sgp++; len += 4; } -- cgit v1.2.3 From d088d6b648f47fc63e0f1d429c6eaddb426623a4 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 6 Jul 2023 09:55:34 +0100 Subject: arm64: dts: arm: Remove the dangling vexpress-v2m-rs1.dtsi symlink Commit 724ba6751532 ("ARM: dts: Move .dts files to vendor sub-directories") moved all arm vendor specific DTS into the sub-directory and updated vexpress-v2f-1xv7-ca53x2.dts accordingly to include vexpress-v2m-rs1.dtsi from the right path. However the symlink was left dangling which is harmless and causes no issue for the build. Just remove the dangling symlink now that it is noticed and reported. Fixes: 724ba6751532 ("ARM: dts: Move .dts files to vendor sub-directories") Cc: Liviu Dudau Cc: Lorenzo Pieralisi Cc: Rob Herring Reported-by: Avram Lubkin Reported-by: Darren Kenny Acked-by: Liviu Dudau Link: https://lore.kernel.org/r/20230706085534.300828-1-sudeep.holla@arm.com Signed-off-by: Sudeep Holla --- arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi | 1 - 1 file changed, 1 deletion(-) delete mode 120000 arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi diff --git a/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi b/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi deleted file mode 120000 index 68fd0f8f1dee..000000000000 --- a/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/vexpress-v2m-rs1.dtsi \ No newline at end of file -- cgit v1.2.3 From d42334578eba1390859012ebb91e1e556d51db49 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 13 Jul 2023 21:59:37 +0900 Subject: exfat: check if filename entries exceeds max filename length exfat_extract_uni_name copies characters from a given file name entry into the 'uniname' variable. This variable is actually defined on the stack of the exfat_readdir() function. According to the definition of the 'exfat_uni_name' type, the file name should be limited 255 characters (+ null teminator space), but the exfat_get_uniname_from_ext_entry() function can write more characters because there is no check if filename entries exceeds max filename length. This patch add the check not to copy filename characters when exceeding max filename length. Cc: stable@vger.kernel.org Cc: Yuezhang Mo Reported-by: Maxim Suhanov Reviewed-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/dir.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 957574180a5e..bc48f3329921 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -34,6 +34,7 @@ static int exfat_get_uniname_from_ext_entry(struct super_block *sb, { int i, err; struct exfat_entry_set_cache es; + unsigned int uni_len = 0, len; err = exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES); if (err) @@ -52,7 +53,10 @@ static int exfat_get_uniname_from_ext_entry(struct super_block *sb, if (exfat_get_entry_type(ep) != TYPE_EXTEND) break; - exfat_extract_uni_name(ep, uniname); + len = exfat_extract_uni_name(ep, uniname); + uni_len += len; + if (len != EXFAT_FILE_NAME_LEN || uni_len >= MAX_NAME_LENGTH) + break; uniname += EXFAT_FILE_NAME_LEN; } @@ -1079,7 +1083,8 @@ rewind: if (entry_type == TYPE_EXTEND) { unsigned short entry_uniname[16], unichar; - if (step != DIRENT_STEP_NAME) { + if (step != DIRENT_STEP_NAME || + name_len >= MAX_NAME_LENGTH) { step = DIRENT_STEP_FILE; continue; } -- cgit v1.2.3 From 37540db221e1ca94d9a57632238d1a62043205b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Thu, 13 Jul 2023 12:18:39 -0500 Subject: MAINTAINERS: Add Manivannan Sadhasivam as DesignWare PCIe driver maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manivannan has been actively reviewing patches and testing changes related to the DesignWare core driver and other DWC-based PCIe drivers for a while now. Add Manivannan as a maintainer for the Synopsys DesignWare driver to make his role and contributions official. Thank you Manivannan! For all the help with DWC! Signed-off-by: Krzysztof WilczyƄski Signed-off-by: Bjorn Helgaas Acked-by: Manivannan Sadhasivam --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc..76bdef7ba1c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16285,6 +16285,7 @@ F: drivers/pci/controller/dwc/pci-exynos.c PCI DRIVER FOR SYNOPSYS DESIGNWARE M: Jingoo Han M: Gustavo Pimentel +M: Manivannan Sadhasivam L: linux-pci@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml -- cgit v1.2.3 From 5def5c1c15bf22934ee227af85c1716762f3829f Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 30 Jun 2023 09:45:33 +0900 Subject: mmc: sdhci-f-sdh30: Replace with sdhci_pltfm Even if sdhci_pltfm_pmops is specified for PM, this driver doesn't apply sdhci_pltfm, so the structure is not correctly referenced in PM functions. This applies sdhci_pltfm to this driver to fix this issue. - Call sdhci_pltfm_init() instead of sdhci_alloc_host() and other functions that covered by sdhci_pltfm. - Move ops and quirks to sdhci_pltfm_data - Replace sdhci_priv() with own private function sdhci_f_sdh30_priv(). Fixes: 87a507459f49 ("mmc: sdhci: host: add new f_sdh30") Signed-off-by: Kunihiko Hayashi Acked-by: Adrian Hunter Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230630004533.26644-1-hayashi.kunihiko@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_f_sdh30.c | 60 ++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index a202a69a4b08..b01ffb4d0973 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -29,9 +29,16 @@ struct f_sdhost_priv { bool enable_cmd_dat_delay; }; +static void *sdhci_f_sdhost_priv(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return sdhci_pltfm_priv(pltfm_host); +} + static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) { - struct f_sdhost_priv *priv = sdhci_priv(host); + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); u32 ctrl = 0; usleep_range(2500, 3000); @@ -64,7 +71,7 @@ static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host) static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) { - struct f_sdhost_priv *priv = sdhci_priv(host); + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); u32 ctl; if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) @@ -95,30 +102,32 @@ static const struct sdhci_ops sdhci_f_sdh30_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; +static const struct sdhci_pltfm_data sdhci_f_sdh30_pltfm_data = { + .ops = &sdhci_f_sdh30_ops, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC + | SDHCI_QUIRK_INVERTED_WRITE_PROTECT, + .quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE + | SDHCI_QUIRK2_TUNING_WORK_AROUND, +}; + static int sdhci_f_sdh30_probe(struct platform_device *pdev) { struct sdhci_host *host; struct device *dev = &pdev->dev; - int irq, ctrl = 0, ret = 0; + int ctrl = 0, ret = 0; struct f_sdhost_priv *priv; + struct sdhci_pltfm_host *pltfm_host; u32 reg = 0; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv)); + host = sdhci_pltfm_init(pdev, &sdhci_f_sdh30_pltfm_data, + sizeof(struct f_sdhost_priv)); if (IS_ERR(host)) return PTR_ERR(host); - priv = sdhci_priv(host); + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); priv->dev = dev; - host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT; - host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | - SDHCI_QUIRK2_TUNING_WORK_AROUND; - priv->enable_cmd_dat_delay = device_property_read_bool(dev, "fujitsu,cmd-dat-delay-select"); @@ -126,18 +135,6 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) if (ret) goto err; - platform_set_drvdata(pdev, host); - - host->hw_name = "f_sdh30"; - host->ops = &sdhci_f_sdh30_ops; - host->irq = irq; - - host->ioaddr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(host->ioaddr)) { - ret = PTR_ERR(host->ioaddr); - goto err; - } - if (dev_of_node(dev)) { sdhci_get_of_property(pdev); @@ -204,24 +201,21 @@ err_rst: err_clk: clk_disable_unprepare(priv->clk_iface); err: - sdhci_free_host(host); + sdhci_pltfm_free(pdev); + return ret; } static int sdhci_f_sdh30_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - struct f_sdhost_priv *priv = sdhci_priv(host); - - sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == - 0xffffffff); + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); reset_control_assert(priv->rst); clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk_iface); - sdhci_free_host(host); - platform_set_drvdata(pdev, NULL); + sdhci_pltfm_unregister(pdev); return 0; } -- cgit v1.2.3 From ff84772fd45d486e4fc78c82e2f70ce5333543e6 Mon Sep 17 00:00:00 2001 From: Sungjong Seo Date: Fri, 14 Jul 2023 17:43:54 +0900 Subject: exfat: release s_lock before calling dir_emit() There is a potential deadlock reported by syzbot as below: ====================================================== WARNING: possible circular locking dependency detected 6.4.0-next-20230707-syzkaller #0 Not tainted ------------------------------------------------------ syz-executor330/5073 is trying to acquire lock: ffff8880218527a0 (&mm->mmap_lock){++++}-{3:3}, at: mmap_read_lock_killable include/linux/mmap_lock.h:151 [inline] ffff8880218527a0 (&mm->mmap_lock){++++}-{3:3}, at: get_mmap_lock_carefully mm/memory.c:5293 [inline] ffff8880218527a0 (&mm->mmap_lock){++++}-{3:3}, at: lock_mm_and_find_vma+0x369/0x510 mm/memory.c:5344 but task is already holding lock: ffff888019f760e0 (&sbi->s_lock){+.+.}-{3:3}, at: exfat_iterate+0x117/0xb50 fs/exfat/dir.c:232 which lock already depends on the new lock. Chain exists of: &mm->mmap_lock --> mapping.invalidate_lock#3 --> &sbi->s_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&sbi->s_lock); lock(mapping.invalidate_lock#3); lock(&sbi->s_lock); rlock(&mm->mmap_lock); Let's try to avoid above potential deadlock condition by moving dir_emit*() out of sbi->s_lock coverage. Fixes: ca06197382bd ("exfat: add directory operations") Cc: stable@vger.kernel.org #v5.7+ Reported-by: syzbot+1741a5d9b79989c10bdc@syzkaller.appspotmail.com Link: https://lore.kernel.org/lkml/00000000000078ee7e060066270b@google.com/T/#u Tested-by: syzbot+1741a5d9b79989c10bdc@syzkaller.appspotmail.com Signed-off-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fs/exfat/dir.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index bc48f3329921..598081d0d059 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -218,7 +218,10 @@ static void exfat_free_namebuf(struct exfat_dentry_namebuf *nb) exfat_init_namebuf(nb); } -/* skip iterating emit_dots when dir is empty */ +/* + * Before calling dir_emit*(), sbi->s_lock should be released + * because page fault can occur in dir_emit*(). + */ #define ITER_POS_FILLED_DOTS (2) static int exfat_iterate(struct file *file, struct dir_context *ctx) { @@ -233,11 +236,10 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) int err = 0, fake_offset = 0; exfat_init_namebuf(nb); - mutex_lock(&EXFAT_SB(sb)->s_lock); cpos = ctx->pos; if (!dir_emit_dots(file, ctx)) - goto unlock; + goto out; if (ctx->pos == ITER_POS_FILLED_DOTS) { cpos = 0; @@ -249,16 +251,18 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) /* name buffer should be allocated before use */ err = exfat_alloc_namebuf(nb); if (err) - goto unlock; + goto out; get_new: + mutex_lock(&EXFAT_SB(sb)->s_lock); + if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode)) goto end_of_dir; err = exfat_readdir(inode, &cpos, &de); if (err) { /* - * At least we tried to read a sector. Move cpos to next sector - * position (should be aligned). + * At least we tried to read a sector. + * Move cpos to next sector position (should be aligned). */ if (err == -EIO) { cpos += 1 << (sb->s_blocksize_bits); @@ -281,16 +285,10 @@ get_new: inum = iunique(sb, EXFAT_ROOT_INO); } - /* - * Before calling dir_emit(), sb_lock should be released. - * Because page fault can occur in dir_emit() when the size - * of buffer given from user is larger than one page size. - */ mutex_unlock(&EXFAT_SB(sb)->s_lock); if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum, (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) - goto out_unlocked; - mutex_lock(&EXFAT_SB(sb)->s_lock); + goto out; ctx->pos = cpos; goto get_new; @@ -298,9 +296,8 @@ end_of_dir: if (!cpos && fake_offset) cpos = ITER_POS_FILLED_DOTS; ctx->pos = cpos; -unlock: mutex_unlock(&EXFAT_SB(sb)->s_lock); -out_unlocked: +out: /* * To improve performance, free namebuf after unlock sb_lock. * If namebuf is not allocated, this function do nothing -- cgit v1.2.3 From d0ca3b92b7a6f42841ea9da8492aaf649db79780 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Fri, 14 Jul 2023 17:21:01 +0200 Subject: mtd: rawnand: rockchip: fix oobfree offset and description Rockchip boot blocks are written per 4 x 512 byte sectors per page. Each page with boot blocks must have a page address (PA) pointer in OOB to the next page. The currently advertised free OOB area starts at offset 6, like if 4 PA bytes were located right after the BBM. This is wrong as the PA bytes are located right before the ECC bytes. Fix the layout by allowing access to all bytes between the BBM and the PA bytes instead of reserving 4 bytes right after the BBM. This change breaks existing jffs2 users. Fixes: 058e0e847d54 ("mtd: rawnand: rockchip: NFC driver for RK3308, RK2928 and others") Signed-off-by: Johan Jonker Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/d202f12d-188c-20e8-f2c2-9cc874ad4d22@gmail.com --- drivers/mtd/nand/raw/rockchip-nand-controller.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 2312e27362cb..37fc07ba57aa 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -562,9 +562,10 @@ static int rk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, * BBM OOB1 OOB2 OOB3 |......| PA0 PA1 PA2 PA3 * * The rk_nfc_ooblayout_free() function already has reserved - * these 4 bytes with: + * these 4 bytes together with 2 bytes for BBM + * by reducing it's length: * - * oob_region->offset = NFC_SYS_DATA_SIZE + 2; + * oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2; */ if (!i) memcpy(rk_nfc_oob_ptr(chip, i), @@ -933,12 +934,8 @@ static int rk_nfc_ooblayout_free(struct mtd_info *mtd, int section, if (section) return -ERANGE; - /* - * The beginning of the OOB area stores the reserved data for the NFC, - * the size of the reserved data is NFC_SYS_DATA_SIZE bytes. - */ oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2; - oob_region->offset = NFC_SYS_DATA_SIZE + 2; + oob_region->offset = 2; return 0; } -- cgit v1.2.3 From ea690ad78dd611e3906df5b948a516000b05c1cb Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Fri, 14 Jul 2023 17:21:21 +0200 Subject: mtd: rawnand: rockchip: Align hwecc vs. raw page helper layouts Currently, read/write_page_hwecc() and read/write_page_raw() are not aligned: there is a mismatch in the OOB bytes which are not read/written at the same offset in both cases (raw vs. hwecc). This is a real problem when relying on the presence of the Page Addresses (PA) when using the NAND chip as a boot device, as the BootROM expects additional data in the OOB area at specific locations. Rockchip boot blocks are written per 4 x 512 byte sectors per page. Each page with boot blocks must have a page address (PA) pointer in OOB to the next page. Pages are written in a pattern depending on the NAND chip ID. Generate boot block page address and pattern for hwecc in user space and copy PA data to/from the already reserved last 4 bytes before ECC in the chip->oob_poi data layout. Align the different helpers. This change breaks existing jffs2 users. Fixes: 058e0e847d54 ("mtd: rawnand: rockchip: NFC driver for RK3308, RK2928 and others") Signed-off-by: Johan Jonker Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/5e782c08-862b-51ae-47ff-3299940928ca@gmail.com --- drivers/mtd/nand/raw/rockchip-nand-controller.c | 34 +++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 37fc07ba57aa..5a04680342c3 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -598,7 +598,7 @@ static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int pages_per_blk = mtd->erasesize / mtd->writesize; int ret = 0, i, boot_rom_mode = 0; dma_addr_t dma_data, dma_oob; - u32 reg; + u32 tmp; u8 *oob; nand_prog_page_begin_op(chip, page, 0, NULL, 0); @@ -625,6 +625,13 @@ static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, * * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ... * + * The code here just swaps the first 4 bytes with the last + * 4 bytes without losing any data. + * + * The chip->oob_poi data layout: + * + * BBM OOB1 OOB2 OOB3 |......| PA0 PA1 PA2 PA3 + * * Configure the ECC algorithm supported by the boot ROM. */ if ((page < (pages_per_blk * rknand->boot_blks)) && @@ -635,21 +642,17 @@ static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, } for (i = 0; i < ecc->steps; i++) { - if (!i) { - reg = 0xFFFFFFFF; - } else { + if (!i) + oob = chip->oob_poi + (ecc->steps - 1) * NFC_SYS_DATA_SIZE; + else oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; - reg = oob[0] | oob[1] << 8 | oob[2] << 16 | - oob[3] << 24; - } - if (!i && boot_rom_mode) - reg = (page & (pages_per_blk - 1)) * 4; + tmp = oob[0] | oob[1] << 8 | oob[2] << 16 | oob[3] << 24; if (nfc->cfg->type == NFC_V9) - nfc->oob_buf[i] = reg; + nfc->oob_buf[i] = tmp; else - nfc->oob_buf[i * (oob_step / 4)] = reg; + nfc->oob_buf[i * (oob_step / 4)] = tmp; } dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf, @@ -812,12 +815,17 @@ static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on, goto timeout_err; } - for (i = 1; i < ecc->steps; i++) { - oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; + for (i = 0; i < ecc->steps; i++) { + if (!i) + oob = chip->oob_poi + (ecc->steps - 1) * NFC_SYS_DATA_SIZE; + else + oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; + if (nfc->cfg->type == NFC_V9) tmp = nfc->oob_buf[i]; else tmp = nfc->oob_buf[i * (oob_step / 4)]; + *oob++ = (u8)tmp; *oob++ = (u8)(tmp >> 8); *oob++ = (u8)(tmp >> 16); -- cgit v1.2.3 From 6bc471b6c3aeaa7b95d1b86a1bb8d91a3c341fa5 Mon Sep 17 00:00:00 2001 From: Alisa Roman Date: Wed, 14 Jun 2023 18:52:43 +0300 Subject: iio: adc: ad7192: Fix ac excitation feature AC excitation enable feature exposed to user on AD7192, allowing a bit which should be 0 to be set. This feature is specific only to AD7195. AC excitation attribute moved accordingly. In the AD7195 documentation, the AC excitation enable bit is on position 22 in the Configuration register. ACX macro changed to match correct register and bit. Note that the fix tag is for the commit that moved the driver out of staging. Fixes: b581f748cce0 ("staging: iio: adc: ad7192: move out of staging") Signed-off-by: Alisa Roman Cc: stable@vger.kernel.org Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20230614155242.160296-1-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 8685e0b58a83..7bc3ebfe8081 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -62,7 +62,6 @@ #define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */ #define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */ #define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */ -#define AD7192_MODE_ACX BIT(14) /* AC excitation enable(AD7195 only)*/ #define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */ #define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/ #define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */ @@ -91,6 +90,7 @@ /* Configuration Register Bit Designations (AD7192_REG_CONF) */ #define AD7192_CONF_CHOP BIT(23) /* CHOP enable */ +#define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */ #define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */ #define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */ #define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */ @@ -472,7 +472,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX)); + return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX)); } static ssize_t ad7192_show_bridge_switch(struct device *dev, @@ -513,13 +513,13 @@ static ssize_t ad7192_set(struct device *dev, ad_sd_write_reg(&st->sd, AD7192_REG_GPOCON, 1, st->gpocon); break; - case AD7192_REG_MODE: + case AD7192_REG_CONF: if (val) - st->mode |= AD7192_MODE_ACX; + st->conf |= AD7192_CONF_ACX; else - st->mode &= ~AD7192_MODE_ACX; + st->conf &= ~AD7192_CONF_ACX; - ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); + ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); break; default: ret = -EINVAL; @@ -579,12 +579,11 @@ static IIO_DEVICE_ATTR(bridge_switch_en, 0644, static IIO_DEVICE_ATTR(ac_excitation_en, 0644, ad7192_show_ac_excitation, ad7192_set, - AD7192_REG_MODE); + AD7192_REG_CONF); static struct attribute *ad7192_attributes[] = { &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, - &iio_dev_attr_ac_excitation_en.dev_attr.attr, NULL }; @@ -595,6 +594,7 @@ static const struct attribute_group ad7192_attribute_group = { static struct attribute *ad7195_attributes[] = { &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, + &iio_dev_attr_ac_excitation_en.dev_attr.attr, NULL }; -- cgit v1.2.3 From d47b9b84292706784482a661324bbc178153781f Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 13 Jun 2023 12:34:36 +0300 Subject: iio: light: bu27034: Fix scale format The driver is expecting accuracy of NANOs for intensity scale in raw_write. The IIO core is however defaulting to MICROs. This leads the raw-write of smallest scales to never succeed as correct selector(s) are not found. Fix this by implementing the .write_raw_get_fmt callback to use NANO accuracy for writes of IIO_CHAN_INFO_SCALE. Signed-off-by: Matti Vaittinen Fixes: e52afbd61039 ("iio: light: ROHM BU27034 Ambient Light Sensor") Link: https://lore.kernel.org/r/5369117315cf05b88cf0ccb87373fd77190f6ca2.1686648422.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/rohm-bu27034.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index e63ef5789cde..bf3de853a811 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -575,7 +575,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, return -EINVAL; if (chan == BU27034_CHAN_ALS) { - if (val == 0 && val2 == 1000) + if (val == 0 && val2 == 1000000) return 0; return -EINVAL; @@ -587,7 +587,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, goto unlock_out; ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, - val, val2 * 1000, &gain_sel); + val, val2, &gain_sel); if (ret) { /* * Could not support scale with given time. Need to change time. @@ -624,7 +624,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, /* Can we provide requested scale with this time? */ ret = iio_gts_find_gain_sel_for_scale_using_time( - &data->gts, new_time_sel, val, val2 * 1000, + &data->gts, new_time_sel, val, val2, &gain_sel); if (ret) continue; @@ -1217,6 +1217,21 @@ static int bu27034_read_raw(struct iio_dev *idev, } } +static int bu27034_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_INT_TIME: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + static int bu27034_write_raw(struct iio_dev *idev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -1267,6 +1282,7 @@ static int bu27034_read_avail(struct iio_dev *idev, static const struct iio_info bu27034_info = { .read_raw = &bu27034_read_raw, .write_raw = &bu27034_write_raw, + .write_raw_get_fmt = &bu27034_write_raw_get_fmt, .read_avail = &bu27034_read_avail, }; -- cgit v1.2.3 From 096649cd7cb0fc1c8f684829f816d938ad1eb808 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 13 Jun 2023 12:34:55 +0300 Subject: iio: light: bu27008: Fix scale format The driver is expecting accuracy of NANOs for intensity scale in raw_write. The IIO core is however defaulting to MICROs. This leads the raw-write of smallest scales to never succeed as correct selector(s) are not found. Fix this by implementing the .write_raw_get_fmt callback to use NANO accuracy for writes of IIO_CHAN_INFO_SCALE. Fixes: 41ff93d14f78 ("iio: light: ROHM BU27008 color sensor") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/e4778b74cde41431f77bc8dd88ec18605da0b400.1686648422.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/rohm-bu27008.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c index 489902bed7f0..80eb14ea8193 100644 --- a/drivers/iio/light/rohm-bu27008.c +++ b/drivers/iio/light/rohm-bu27008.c @@ -633,7 +633,7 @@ static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val, for (i = 0; i < data->gts.num_itime; i++) { new_time_sel = data->gts.itime_table[i].sel; ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, - new_time_sel, val, val2 * 1000, gain_sel); + new_time_sel, val, val2, gain_sel); if (!ret) break; } @@ -662,7 +662,7 @@ static int bu27008_set_scale(struct bu27008_data *data, goto unlock_out; ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, - val, val2 * 1000, &gain_sel); + val, val2, &gain_sel); if (ret) { ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel); if (ret) @@ -677,6 +677,21 @@ unlock_out: return ret; } +static int bu27008_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_INT_TIME: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + static int bu27008_write_raw(struct iio_dev *idev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -756,6 +771,7 @@ static int bu27008_update_scan_mode(struct iio_dev *idev, static const struct iio_info bu27008_info = { .read_raw = &bu27008_read_raw, .write_raw = &bu27008_write_raw, + .write_raw_get_fmt = &bu27008_write_raw_get_fmt, .read_avail = &bu27008_read_avail, .update_scan_mode = bu27008_update_scan_mode, .validate_trigger = iio_validate_own_trigger, -- cgit v1.2.3 From 95fb1e7b23bc82130016daefa02a87e83185ca95 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 13 Jun 2023 12:35:12 +0300 Subject: iio: light: bu27008: Fix intensity data type The intensity data from bu27008 is unsigned. The type of the scan data was incorrectly marked as signed resulting large intensity values to be interpreted as negative ones. Fix the scan data type. Fixes: 41ff93d14f78 ("iio: light: ROHM BU27008 color sensor") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/240a7ca5fc1b76da20d81f930d00f31a54b1fdf8.1686648422.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/rohm-bu27008.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c index 80eb14ea8193..b50bf8973d9a 100644 --- a/drivers/iio/light/rohm-bu27008.c +++ b/drivers/iio/light/rohm-bu27008.c @@ -190,7 +190,7 @@ static const struct iio_itime_sel_mul bu27008_itimes[] = { .address = BU27008_REG_##data##_LO, \ .scan_index = BU27008_##color, \ .scan_type = { \ - .sign = 's', \ + .sign = 'u', \ .realbits = 16, \ .storagebits = 16, \ .endianness = IIO_LE, \ -- cgit v1.2.3 From a41e19cc0d6b6a445a4133170b90271e4a2553dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Mon, 19 Jun 2023 16:12:39 +0200 Subject: iio: adc: ina2xx: avoid NULL pointer dereference on OF device match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The affected lines were resulting in a NULL pointer dereference on our platform because the device tree contained the following list of compatible strings: power-sensor@40 { compatible = "ti,ina232", "ti,ina231"; ... }; Since the driver doesn't declare a compatible string "ti,ina232", the OF matching succeeds on "ti,ina231". But the I2C device ID info is populated via the first compatible string, cf. modalias population in of_i2c_get_board_info(). Since there is no "ina232" entry in the legacy I2C device ID table either, the struct i2c_device_id *id pointer in the probe function is NULL. Fix this by using the already populated type variable instead, which points to the proper driver data. Since the name is also wanted, add a generic one to the ina2xx_config table. Signed-off-by: Alvin Ć ipraga Fixes: c43a102e67db ("iio: ina2xx: add support for TI INA2xx Power Monitors") Link: https://lore.kernel.org/r/20230619141239.2257392-1-alvin@pqrs.dk Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 213526c1592f..aea83f369437 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -124,6 +124,7 @@ static const struct regmap_config ina2xx_regmap_config = { enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { + const char *name; u16 config_default; int calibration_value; int shunt_voltage_lsb; /* nV */ @@ -155,6 +156,7 @@ struct ina2xx_chip_info { static const struct ina2xx_config ina2xx_config[] = { [ina219] = { + .name = "ina219", .config_default = INA219_CONFIG_DEFAULT, .calibration_value = 4096, .shunt_voltage_lsb = 10000, @@ -164,6 +166,7 @@ static const struct ina2xx_config ina2xx_config[] = { .chip_id = ina219, }, [ina226] = { + .name = "ina226", .config_default = INA226_CONFIG_DEFAULT, .calibration_value = 2048, .shunt_voltage_lsb = 2500, @@ -996,7 +999,7 @@ static int ina2xx_probe(struct i2c_client *client) /* Patch the current config register with default. */ val = chip->config->config_default; - if (id->driver_data == ina226) { + if (type == ina226) { ina226_set_average(chip, INA226_DEFAULT_AVG, &val); ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val); ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val); @@ -1015,7 +1018,7 @@ static int ina2xx_probe(struct i2c_client *client) } indio_dev->modes = INDIO_DIRECT_MODE; - if (id->driver_data == ina226) { + if (type == ina226) { indio_dev->channels = ina226_channels; indio_dev->num_channels = ARRAY_SIZE(ina226_channels); indio_dev->info = &ina226_info; @@ -1024,7 +1027,7 @@ static int ina2xx_probe(struct i2c_client *client) indio_dev->num_channels = ARRAY_SIZE(ina219_channels); indio_dev->info = &ina219_info; } - indio_dev->name = id->name; + indio_dev->name = id ? id->name : chip->config->name; ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, &ina2xx_setup_ops); -- cgit v1.2.3 From 48faabfb3634e519fc49ef01525448ad2ba96751 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jul 2023 10:05:12 +0200 Subject: dt-bindings: iio: adi,ad74115: remove ref from -nanoamp dtschema v2023.06 comes with support for properties with -nanoamp suffix, thus bindings should not have a ref for it: adi,ad74115.yaml: properties:adi,ext1-burnout-current-nanoamp: '$ref' should not be valid under {'const': '$ref'} Cc: Cosmin Tanislav Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230712080512.94964-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml index 72d2e910f206..2594fa192f93 100644 --- a/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml +++ b/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml @@ -216,7 +216,6 @@ properties: description: Whether to enable burnout current for EXT1. adi,ext1-burnout-current-nanoamp: - $ref: /schemas/types.yaml#/definitions/uint32 description: Burnout current in nanoamps to be applied to EXT1. enum: [0, 50, 500, 1000, 10000] @@ -233,7 +232,6 @@ properties: description: Whether to enable burnout current for EXT2. adi,ext2-burnout-current-nanoamp: - $ref: /schemas/types.yaml#/definitions/uint32 description: Burnout current in nanoamps to be applied to EXT2. enum: [0, 50, 500, 1000, 10000] default: 0 @@ -249,7 +247,6 @@ properties: description: Whether to enable burnout current for VIOUT. adi,viout-burnout-current-nanoamp: - $ref: /schemas/types.yaml#/definitions/uint32 description: Burnout current in nanoamps to be applied to VIOUT. enum: [0, 1000, 10000] default: 0 -- cgit v1.2.3 From 3e7d3c5e13b05dda9db92d98803a626378e75438 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 6 Jun 2023 08:39:45 -0700 Subject: arm64: dts: imx8mm-venice-gw7903: disable disp_blk_ctrl The GW7903 does not connect the VDD_MIPI power rails thus MIPI is disabled. However we must also disable disp_blk_ctrl as it uses the pgc_mipi power domain and without it being disabled imx8m-blk-ctrl will fail to probe: imx8m-blk-ctrl 32e28000.blk-ctrl: error -ETIMEDOUT: failed to attach power domain "mipi-dsi" imx8m-blk-ctrl: probe of 32e28000.blk-ctrl failed with error -110 Fixes: a72ba91e5bc7 ("arm64: dts: imx: Add i.mx8mm Gateworks gw7903 dts support") Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts index 6f26914602c8..07b07dc954fd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts @@ -567,6 +567,10 @@ status = "okay"; }; +&disp_blk_ctrl { + status = "disabled"; +}; + &pgc_mipi { status = "disabled"; }; -- cgit v1.2.3 From f7a0b57524cf811ac06257a5099f1b7c19ee7310 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 6 Jun 2023 08:40:30 -0700 Subject: arm64: dts: imx8mm-venice-gw7904: disable disp_blk_ctrl The GW7904 does not connect the VDD_MIPI power rails thus MIPI is disabled. However we must also disable disp_blk_ctrl as it uses the pgc_mipi power domain and without it being disabled imx8m-blk-ctrl will fail to probe: imx8m-blk-ctrl 32e28000.blk-ctrl: error -ETIMEDOUT: failed to attach power domain "mipi-dsi" imx8m-blk-ctrl: probe of 32e28000.blk-ctrl failed with error -110 Fixes: b999bdaf0597 ("arm64: dts: imx: Add i.mx8mm Gateworks gw7904 dts support") Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts index 93088fa1c3b9..d5b716855812 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts @@ -628,6 +628,10 @@ status = "okay"; }; +&disp_blk_ctrl { + status = "disabled"; +}; + &pgc_mipi { status = "disabled"; }; -- cgit v1.2.3 From dcb60f9c403e03133363563ac8ea5d8bba6c2be1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 Jul 2023 20:08:32 -0700 Subject: cpumask: eliminate kernel-doc warnings Update lib/cpumask.c and to fix all kernel-doc warnings: include/linux/cpumask.h:185: warning: Function parameter or member 'srcp1' not described in 'cpumask_first_and' include/linux/cpumask.h:185: warning: Function parameter or member 'srcp2' not described in 'cpumask_first_and' include/linux/cpumask.h:185: warning: Excess function parameter 'src1p' description in 'cpumask_first_and' include/linux/cpumask.h:185: warning: Excess function parameter 'src2p' description in 'cpumask_first_and' lib/cpumask.c:59: warning: Function parameter or member 'node' not described in 'alloc_cpumask_var_node' lib/cpumask.c:169: warning: Function parameter or member 'src1p' not described in 'cpumask_any_and_distribute' lib/cpumask.c:169: warning: Function parameter or member 'src2p' not described in 'cpumask_any_and_distribute' Fixes: 7b4967c53204 ("cpumask: Add alloc_cpumask_var_node()") Fixes: 839cad5fa54b ("cpumask: fix function description kernel-doc notation") Fixes: 93ba139ba819 ("cpumask: use find_first_and_bit()") Signed-off-by: Randy Dunlap Reviewed-by: Andy Shevchenko Signed-off-by: Yury Norov --- include/linux/cpumask.h | 8 ++++++-- lib/cpumask.c | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 0d2e2a38b92d..f10fb87d49db 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -175,8 +175,8 @@ static inline unsigned int cpumask_first_zero(const struct cpumask *srcp) /** * cpumask_first_and - return the first cpu from *srcp1 & *srcp2 - * @src1p: the first input - * @src2p: the second input + * @srcp1: the first input + * @srcp2: the second input * * Returns >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and(). */ @@ -1197,6 +1197,10 @@ cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask, /** * cpumap_print_list_to_buf - copies the cpumask into the buffer as * comma-separated list of cpus + * @buf: the buffer to copy into + * @mask: the cpumask to copy + * @off: in the string from which we are copying, we copy to @buf + * @count: the maximum number of bytes to print * * Everything is same with the above cpumap_print_bitmask_to_buf() * except the print format. diff --git a/lib/cpumask.c b/lib/cpumask.c index de356f16773a..a7fd02b5ae26 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -45,6 +45,7 @@ EXPORT_SYMBOL(cpumask_next_wrap); * alloc_cpumask_var_node - allocate a struct cpumask on a given node * @mask: pointer to cpumask_var_t where the cpumask is returned * @flags: GFP_ flags + * @node: memory node from which to allocate or %NUMA_NO_NODE * * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is * a nop returning a constant 1 (in ) @@ -157,7 +158,9 @@ EXPORT_SYMBOL(cpumask_local_spread); static DEFINE_PER_CPU(int, distribute_cpu_mask_prev); /** - * cpumask_any_and_distribute - Return an arbitrary cpu within srcp1 & srcp2. + * cpumask_any_and_distribute - Return an arbitrary cpu within src1p & src2p. + * @src1p: first &cpumask for intersection + * @src2p: second &cpumask for intersection * * Iterated calls using the same srcp1 and srcp2 will be distributed within * their intersection. -- cgit v1.2.3 From ee70b908f77a9d8f689dea986f09e6d7dc481934 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Mon, 17 Jul 2023 10:28:33 +0800 Subject: ARM: dts: nxp/imx6sll: fix wrong property name in usbphy node Property name "phy-3p0-supply" is used instead of "phy-reg_3p0-supply". Fixes: 9f30b6b1a957 ("ARM: dts: imx: Add basic dtsi file for imx6sll") cc: Signed-off-by: Xu Yang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx6sll.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi index 2873369a57c0..3659fd5ecfa6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi @@ -552,7 +552,7 @@ reg = <0x020ca000 0x1000>; interrupts = ; clocks = <&clks IMX6SLL_CLK_USBPHY2>; - phy-reg_3p0-supply = <®_3p0>; + phy-3p0-supply = <®_3p0>; fsl,anatop = <&anatop>; }; -- cgit v1.2.3 From cddeefc1663294fb74b31ff5029a83c0e819ff3a Mon Sep 17 00:00:00 2001 From: Yashwanth Varakala Date: Fri, 16 Jun 2023 11:50:07 +0200 Subject: arm64: dts: phycore-imx8mm: Label typo-fix of VPU Corrected the label of the VPU regulator node (buck 3) from reg_vdd_gpu to reg_vdd_vpu. Fixes: ae6847f26ac9 ("arm64: dts: freescale: Add phyBOARD-Polis-i.MX8MM support") Signed-off-by: Yashwanth Varakala Signed-off-by: Cem Tenruh Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi index 92616bc4f71f..2dd179ec923d 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi @@ -210,7 +210,7 @@ }; }; - reg_vdd_gpu: buck3 { + reg_vdd_vpu: buck3 { regulator-always-on; regulator-boot-on; regulator-max-microvolt = <1000000>; -- cgit v1.2.3 From 1ef0aa137a96c5f0564f2db0c556a4f0f60ce8f5 Mon Sep 17 00:00:00 2001 From: Yashwanth Varakala Date: Fri, 16 Jun 2023 11:50:09 +0200 Subject: arm64: dts: phycore-imx8mm: Correction in gpio-line-names Remove unused nINT_ETHPHY entry from gpio-line-names in gpio1 nodes of phyCORE-i.MX8MM and phyBOARD-Polis-i.MX8MM devicetrees. Fixes: ae6847f26ac9 ("arm64: dts: freescale: Add phyBOARD-Polis-i.MX8MM support") Signed-off-by: Yashwanth Varakala Signed-off-by: Cem Tenruh Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts | 2 +- arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts index 03e7679217b2..479948f8a4b7 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts @@ -141,7 +141,7 @@ }; &gpio1 { - gpio-line-names = "nINT_ETHPHY", "LED_RED", "WDOG_INT", "X_RTC_INT", + gpio-line-names = "", "LED_RED", "WDOG_INT", "X_RTC_INT", "", "", "", "RESET_ETHPHY", "CAN_nINT", "CAN_EN", "nENABLE_FLATLINK", "", "USB_OTG_VBUS_EN", "", "LED_GREEN", "LED_BLUE"; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi index 2dd179ec923d..847f08537b48 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi @@ -111,7 +111,7 @@ }; &gpio1 { - gpio-line-names = "nINT_ETHPHY", "", "WDOG_INT", "X_RTC_INT", + gpio-line-names = "", "", "WDOG_INT", "X_RTC_INT", "", "", "", "RESET_ETHPHY", "", "", "nENABLE_FLATLINK"; }; -- cgit v1.2.3 From 253be5b53c2792fb4384f8005b05421e6f040ee3 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 4 Jul 2023 09:48:00 -0400 Subject: arm64: dts: imx8mn-var-som: add missing pull-up for onboard PHY reset pinmux For SOMs with an onboard PHY, the RESET_N pull-up resistor is currently deactivated in the pinmux configuration. When the pinmux code selects the GPIO function for this pin, with a default direction of input, this prevents the RESET_N pin from being taken to the proper 3.3V level (deasserted), and this results in the PHY being not detected since it is held in reset. Taken from RESET_N pin description in ADIN13000 datasheet: This pin requires a 1K pull-up resistor to AVDD_3P3. Activate the pull-up resistor to fix the issue. Fixes: ade0176dd8a0 ("arm64: dts: imx8mn-var-som: Add Variscite VAR-SOM-MX8MN System on Module") Signed-off-by: Hugo Villeneuve Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi index d3a67109d55b..b8946edf317b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi @@ -358,7 +358,7 @@ MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f - MX8MN_IOMUXC_GPIO1_IO09_GPIO1_IO9 0x19 + MX8MN_IOMUXC_GPIO1_IO09_GPIO1_IO9 0x159 >; }; -- cgit v1.2.3 From b27bfc5103c72f84859bd32731b6a09eafdeda05 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 7 Jul 2023 11:42:00 +0200 Subject: arm64: dts: freescale: Fix VPU G2 clock Set VPU G2 clock to 300MHz like described in documentation. This fixes pixels error occurring with large resolution ( >= 2560x1600) HEVC test stream when using the postprocessor to produce NV12. Fixes: 4ac7e4a81272 ("arm64: dts: imx8mq: Enable both G1 and G2 VPU's with vpu-blk-ctrl") Signed-off-by: Benjamin Gaignard Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mq.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index 1a2d2c04db32..01eec424f7f7 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -772,7 +772,7 @@ <&clk IMX8MQ_SYS1_PLL_800M>, <&clk IMX8MQ_VPU_PLL>; assigned-clock-rates = <600000000>, - <600000000>, + <300000000>, <800000000>, <0>; }; -- cgit v1.2.3 From 0e52740ffd10c6c316837c6c128f460f1aaba1ea Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sat, 8 Jul 2023 10:21:35 +0200 Subject: x86/bugs: Increase the x86 bugs vector size to two u32s There was never a doubt in my mind that they would not fit into a single u32 eventually. Signed-off-by: Borislav Petkov (AMD) --- arch/x86/include/asm/cpufeatures.h | 2 +- tools/arch/x86/include/asm/cpufeatures.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index cb8ca46213be..1f6d904c6481 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -14,7 +14,7 @@ * Defines x86 CPU feature bits */ #define NCAPINTS 21 /* N 32-bit words worth of info */ -#define NBUGINTS 1 /* N 32-bit bug flags */ +#define NBUGINTS 2 /* N 32-bit bug flags */ /* * Note: If the comment begins with a quoted string, that string is used diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index cb8ca46213be..1f6d904c6481 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -14,7 +14,7 @@ * Defines x86 CPU feature bits */ #define NCAPINTS 21 /* N 32-bit words worth of info */ -#define NBUGINTS 1 /* N 32-bit bug flags */ +#define NBUGINTS 2 /* N 32-bit bug flags */ /* * Note: If the comment begins with a quoted string, that string is used -- cgit v1.2.3 From d05799d7b4a39fa71c65aa277128ac7c843ffcdc Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Mon, 17 Jul 2023 18:17:02 +0100 Subject: firmware: smccc: Fix use of uninitialised results structure Commit 35727af2b15d ("irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4") moved the initialisation of the SoC version to arm_smccc_version_init() but forgot to update the results structure and it's usage. Fix the use of the uninitialised results structure and update the error strings. Fixes: 35727af2b15d ("irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4") Signed-off-by: Punit Agrawal Cc: Sudeep Holla Cc: Marc Zyngier Cc: Vikram Sethi Cc: Shanker Donthineni Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20230717171702.424253-1-punit.agrawal@bytedance.com Signed-off-by: Sudeep Holla --- drivers/firmware/smccc/soc_id.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/smccc/soc_id.c b/drivers/firmware/smccc/soc_id.c index 890eb454599a..1990263fbba0 100644 --- a/drivers/firmware/smccc/soc_id.c +++ b/drivers/firmware/smccc/soc_id.c @@ -34,7 +34,6 @@ static struct soc_device_attribute *soc_dev_attr; static int __init smccc_soc_init(void) { - struct arm_smccc_res res; int soc_id_rev, soc_id_version; static char soc_id_str[20], soc_id_rev_str[12]; static char soc_id_jep106_id_str[12]; @@ -49,13 +48,13 @@ static int __init smccc_soc_init(void) } if (soc_id_version < 0) { - pr_err("ARCH_SOC_ID(0) returned error: %lx\n", res.a0); + pr_err("Invalid SoC Version: %x\n", soc_id_version); return -EINVAL; } soc_id_rev = arm_smccc_get_soc_id_revision(); if (soc_id_rev < 0) { - pr_err("ARCH_SOC_ID(1) returned error: %lx\n", res.a0); + pr_err("Invalid SoC Revision: %x\n", soc_id_rev); return -EINVAL; } -- cgit v1.2.3 From 81b233b8dd72f2d1df3da8bd4bd4f8c5e84937b9 Mon Sep 17 00:00:00 2001 From: Sukrut Bellary Date: Tue, 18 Jul 2023 01:55:29 -0700 Subject: firmware: arm_scmi: Fix signed error return values handling Handle signed error return values returned by simple_write_to_buffer(). In case of an error, return the error code. Fixes: 3c3d818a9317 ("firmware: arm_scmi: Add core raw transmission support") Reported-by: Dan Carpenter Signed-off-by: Sukrut Bellary Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20230718085529.258899-1-sukrut.bellary@linux.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/raw_mode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index 6971dcf72fb9..0493aa3c12bf 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -818,10 +818,13 @@ static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp, * before sending it with a single RAW xfer. */ if (rd->tx_size < rd->tx_req_size) { - size_t cnt; + ssize_t cnt; cnt = simple_write_to_buffer(rd->tx.buf, rd->tx.len, ppos, buf, count); + if (cnt < 0) + return cnt; + rd->tx_size += cnt; if (cnt < count) return cnt; -- cgit v1.2.3 From 2356d198d2b4ddec24efea98271cb3be230bc787 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 17 Jul 2023 12:17:03 -0700 Subject: lib/bitmap: workaround const_eval test build failure When building with Clang, and when KASAN and GCOV_PROFILE_ALL are both enabled, the test fails to build [1]: >> lib/test_bitmap.c:920:2: error: call to '__compiletime_assert_239' declared with 'error' attribute: BUILD_BUG_ON failed: !__builtin_constant_p(res) BUILD_BUG_ON(!__builtin_constant_p(res)); ^ include/linux/build_bug.h:50:2: note: expanded from macro 'BUILD_BUG_ON' BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) ^ include/linux/build_bug.h:39:37: note: expanded from macro 'BUILD_BUG_ON_MSG' #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) ^ include/linux/compiler_types.h:352:2: note: expanded from macro 'compiletime_assert' _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ^ include/linux/compiler_types.h:340:2: note: expanded from macro '_compiletime_assert' __compiletime_assert(condition, msg, prefix, suffix) ^ include/linux/compiler_types.h:333:4: note: expanded from macro '__compiletime_assert' prefix ## suffix(); \ ^ :185:1: note: expanded from here __compiletime_assert_239 Originally it was attributed to s390, which now looks seemingly wrong. The issue is not related to bitmap code itself, but it breaks build for a given configuration. Disabling the const_eval test under that config may potentially hide other bugs. Instead, workaround it by disabling GCOV for the test_bitmap unless the compiler will get fixed. [1] https://github.com/ClangBuiltLinux/linux/issues/1874 Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307171254.yFcH97ej-lkp@intel.com/ Fixes: dc34d5036692 ("lib: test_bitmap: add compile-time optimization/evaluations assertions") Co-developed-by: Nathan Chancellor Signed-off-by: Nathan Chancellor Signed-off-by: Yury Norov Reviewed-by: Nick Desaulniers Reviewed-by: Alexander Lobakin --- lib/Makefile | 6 ++++++ lib/test_bitmap.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 42d307ade225..1ffae65bb7ee 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -82,7 +82,13 @@ obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o obj-$(CONFIG_TEST_PRINTF) += test_printf.o obj-$(CONFIG_TEST_SCANF) += test_scanf.o + obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o +ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy) +# FIXME: Clang breaks test_bitmap_const_eval when KASAN and GCOV are enabled +GCOV_PROFILE_test_bitmap.o := n +endif + obj-$(CONFIG_TEST_UUID) += test_uuid.o obj-$(CONFIG_TEST_XARRAY) += test_xarray.o obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 187f5b2db4cf..f2ea9f30c7c5 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -1161,6 +1161,10 @@ static void __init test_bitmap_print_buf(void) } } +/* + * FIXME: Clang breaks compile-time evaluations when KASAN and GCOV are enabled. + * To workaround it, GCOV is force-disabled in Makefile for this configuration. + */ static void __init test_bitmap_const_eval(void) { DECLARE_BITMAP(bitmap, BITS_PER_LONG); @@ -1186,11 +1190,7 @@ static void __init test_bitmap_const_eval(void) * the compiler is fixed. */ bitmap_clear(bitmap, 0, BITS_PER_LONG); -#if defined(__s390__) && defined(__clang__) - if (!const_test_bit(7, bitmap)) -#else if (!test_bit(7, bitmap)) -#endif bitmap_set(bitmap, 5, 2); /* Equals to `unsigned long bitopvar = BIT(20)` */ -- cgit v1.2.3 From c486762fb17c99fd642beea3e1e4744d093c262a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 9 Jul 2023 23:30:19 +0300 Subject: ARM: dts: nxp/imx: limit sk-imx53 supported frequencies The SK-IMX53 board, bearing i.MX536A CPU, is not stable when running at 1.2 GHz (default iMX53 maximum). The SoC is only rated up to 800 MHz. Disable 1.2 GHz and 1 GHz frequencies. Fixes: 0b8576d8440a ("ARM: dts: imx: Add support for SK-iMX53 board") Signed-off-by: Dmitry Baryshkov Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/nxp/imx/imx53-sk-imx53.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/nxp/imx/imx53-sk-imx53.dts b/arch/arm/boot/dts/nxp/imx/imx53-sk-imx53.dts index 103e73176e47..1a00d290092a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-sk-imx53.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-sk-imx53.dts @@ -60,6 +60,16 @@ status = "okay"; }; +&cpu0 { + /* CPU rated to 800 MHz, not the default 1.2GHz. */ + operating-points = < + /* kHz uV */ + 166666 850000 + 400000 900000 + 800000 1050000 + >; +}; + &ecspi1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi1>; -- cgit v1.2.3 From 53cab4d871690c49fac87c657cbf459e39c5b93b Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 17 Jul 2023 16:54:09 +0200 Subject: soc: imx: imx8mp-blk-ctrl: register HSIO PLL clock as bus_power_dev child The blk-ctrl device is deliberately placed outside of the GPC power domain as it needs to control the power sequencing of the blk-ctrl domains together with the GPC domains. Clock runtime PM works by operating on the clock parent device, which doesn't translate into the neccessary GPC power domain action if the clk parent is not part of the GPC power domain. Use the bus_power_device as the parent for the clock to trigger the proper GPC domain actions on clock runtime power management. Fixes: 2cbee26e5d59 ("soc: imx: imx8mp-blk-ctrl: expose high performance PLL clock") Reported-by: Yannic Moog Signed-off-by: Lucas Stach Tested-by: Yannic Moog Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8mp-blk-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 870aecc0202a..1c1fcab4979a 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -164,7 +164,7 @@ static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc) clk_hsio_pll->hw.init = &init; hw = &clk_hsio_pll->hw; - ret = devm_clk_hw_register(bc->dev, hw); + ret = devm_clk_hw_register(bc->bus_power_dev, hw); if (ret) return ret; -- cgit v1.2.3 From 84f68679032147dcdac9bb4d8eb8f4638e995dc6 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 18 Jul 2023 18:45:37 +0000 Subject: KVM: arm64: Allow pKVM on v1.0 compatible FF-A implementations pKVM initialization fails on systems with v1.1+ FF-A implementations, as the hyp does a strict match on the returned version from FFA_VERSION. This is a stronger assertion than required by the specification, which requires minor revisions be backwards compatible with earlier revisions of the same major version. Relax the check in hyp_ffa_init() to only test the returned major version. Even though v1.1 broke ABI, the expectation is that firmware incapable of using the v1.0 ABI return NOT_SUPPORTED instead of a valid version. Acked-by: Marc Zyngier Acked-by: Will Deacon Link: https://lore.kernel.org/r/20230718184537.3220867-1-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/ffa.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 58dcd92bf346..ab4f5d160c58 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -705,7 +705,20 @@ int hyp_ffa_init(void *pages) if (res.a0 == FFA_RET_NOT_SUPPORTED) return 0; - if (res.a0 != FFA_VERSION_1_0) + /* + * Firmware returns the maximum supported version of the FF-A + * implementation. Check that the returned version is + * backwards-compatible with the hyp according to the rules in DEN0077A + * v1.1 REL0 13.2.1. + * + * Of course, things are never simple when dealing with firmware. v1.1 + * broke ABI with v1.0 on several structures, which is itself + * incompatible with the aforementioned versioning scheme. The + * expectation is that v1.x implementations that do not support the v1.0 + * ABI return NOT_SUPPORTED rather than a version number, according to + * DEN0077A v1.1 REL0 18.6.4. + */ + if (FFA_MAJOR_VERSION(res.a0) != 1) return -EOPNOTSUPP; arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res); -- cgit v1.2.3 From da042eb4f061a0b54aedadcaa15391490c48e1ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 19 Jul 2023 08:16:52 +0200 Subject: firmware: arm_scmi: Drop OF node reference in the transport channel setup The OF node reference obtained from of_parse_phandle() should be dropped if node is not compatible with arm,scmi-shmem. Fixes: 507cd4d2c5eb ("firmware: arm_scmi: Add compatibility checks for shmem node") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Cristian Marussi Link: https://lore.kernel.org/r/20230719061652.8850-1-krzysztof.kozlowski@linaro.org Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/mailbox.c | 4 +++- drivers/firmware/arm_scmi/smc.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 1efa5e9392c4..19246ed1f01f 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -166,8 +166,10 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, return -ENOMEM; shmem = of_parse_phandle(cdev->of_node, "shmem", idx); - if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) + if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) { + of_node_put(shmem); return -ENXIO; + } ret = of_address_to_resource(shmem, 0, &res); of_node_put(shmem); diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 621c37efe3ec..2d8c510fbf52 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -137,8 +137,10 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, return -ENOMEM; np = of_parse_phandle(cdev->of_node, "shmem", 0); - if (!of_device_is_compatible(np, "arm,scmi-shmem")) + if (!of_device_is_compatible(np, "arm,scmi-shmem")) { + of_node_put(np); return -ENXIO; + } ret = of_address_to_resource(np, 0, &res); of_node_put(np); -- cgit v1.2.3 From 1eb8d61ac5c9c7ec56bb96d433532807509b9288 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 19 Jul 2023 15:42:50 +0800 Subject: clk: mediatek: mt8183: Add back SSPM related clocks This reverts commit 860690a93ef23b567f781c1b631623e27190f101. On the MT8183, the SSPM related clocks were removed claiming a lack of usage. This however causes some issues when the driver was converted to the new simple-probe mechanism. This mechanism allocates enough space for all the clocks defined in the clock driver, not the highest index in the DT binding. This leads to out-of-bound writes if their are holes in the DT binding or the driver (due to deprecated or unimplemented clocks). These errors can go unnoticed and cause memory corruption, leading to crashes in unrelated areas, or nothing at all. KASAN will detect them. Add the SSPM related clocks back to the MT8183 clock driver to fully implement the DT binding. The SSPM clocks are for the power management co-processor, and should never be turned off. They are marked as such. Fixes: 3f37ba7cc385 ("clk: mediatek: mt8183: Convert all remaining clocks to common probe") Signed-off-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20230719074251.1219089-1-wenst@chromium.org Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8183.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c index 1ba421b38ec5..e31f94387d87 100644 --- a/drivers/clk/mediatek/clk-mt8183.c +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -328,6 +328,14 @@ static const char * const atb_parents[] = { "syspll_d5" }; +static const char * const sspm_parents[] = { + "clk26m", + "univpll_d2_d4", + "syspll_d2_d2", + "univpll_d2_d2", + "syspll_d3" +}; + static const char * const dpi0_parents[] = { "clk26m", "tvdpll_d2", @@ -507,6 +515,9 @@ static const struct mtk_mux top_muxes[] = { /* CLK_CFG_6 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel", atb_parents, 0xa0, 0xa4, 0xa8, 0, 2, 7, 0x004, 24), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MUX_SSPM, "sspm_sel", + sspm_parents, 0xa0, 0xa4, 0xa8, 8, 3, 15, 0x004, 25, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel", dpi0_parents, 0xa0, 0xa4, 0xa8, 16, 4, 23, 0x004, 26), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SCAM, "scam_sel", @@ -673,10 +684,18 @@ static const struct mtk_gate_regs infra3_cg_regs = { GATE_MTK(_id, _name, _parent, &infra2_cg_regs, _shift, \ &mtk_clk_gate_ops_setclr) +#define GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra2_cg_regs, \ + _shift, &mtk_clk_gate_ops_setclr, _flag) + #define GATE_INFRA3(_id, _name, _parent, _shift) \ GATE_MTK(_id, _name, _parent, &infra3_cg_regs, _shift, \ &mtk_clk_gate_ops_setclr) +#define GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra3_cg_regs, \ + _shift, &mtk_clk_gate_ops_setclr, _flag) + static const struct mtk_gate infra_clks[] = { /* INFRA0 */ GATE_INFRA0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr", "axi_sel", 0), @@ -748,7 +767,11 @@ static const struct mtk_gate infra_clks[] = { GATE_INFRA2(CLK_INFRA_UNIPRO_TICK, "infra_unipro_tick", "fufs_sel", 12), GATE_INFRA2(CLK_INFRA_UFS_MP_SAP_BCLK, "infra_ufs_mp_sap_bck", "fufs_sel", 13), GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk", "axi_sel", 14), + /* infra_sspm is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA2_FLAGS(CLK_INFRA_SSPM, "infra_sspm", "sspm_sel", 15, CLK_IS_CRITICAL), GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist", "axi_sel", 16), + /* infra_sspm_bus_hclk is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA2_FLAGS(CLK_INFRA_SSPM_BUS_HCLK, "infra_sspm_bus_hclk", "axi_sel", 17, CLK_IS_CRITICAL), GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5", "i2c_sel", 18), GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter", "i2c_sel", 19), GATE_INFRA2(CLK_INFRA_I2C5_IMM, "infra_i2c5_imm", "i2c_sel", 20), @@ -766,6 +789,10 @@ static const struct mtk_gate infra_clks[] = { GATE_INFRA3(CLK_INFRA_MSDC0_SELF, "infra_msdc0_self", "msdc50_0_sel", 0), GATE_INFRA3(CLK_INFRA_MSDC1_SELF, "infra_msdc1_self", "msdc50_0_sel", 1), GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self", "msdc50_0_sel", 2), + /* infra_sspm_26m_self is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self", "f_f26m_ck", 3, CLK_IS_CRITICAL), + /* infra_sspm_32k_self is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", "f_f26m_ck", 4, CLK_IS_CRITICAL), GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", "axi_sel", 5), GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", "i2c_sel", 6), GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", "msdc50_hclk_sel", 7), -- cgit v1.2.3 From a29b2fccf5f2689a9637be85ff1f51c834c6fb33 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Jul 2023 17:08:12 +0200 Subject: clk: imx93: Propagate correct error in imx93_clocks_probe() smatch reports: drivers/clk/imx/clk-imx93.c:294 imx93_clocks_probe() error: uninitialized symbol 'base'. Indeed, in case of an error, the wrong (yet uninitialized) variable is converted to an error code and returned. Fix this by propagating the error code in the correct variable. Fixes: e02ba11b45764705 ("clk: imx93: fix memory leak and missing unwind goto in imx93_clocks_probe") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/9c2acd81-3ad8-485d-819e-9e4201277831@kadam.mountain Reported-by: kernel test robot Closes: https://lore.kernel.org/all/202306161533.4YDmL22b-lkp@intel.com/ Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230711150812.3562221-1-geert+renesas@glider.be Reviewed-by: Peng Fan Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx93.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index b6c7c2725906..44f435103c65 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -291,7 +291,7 @@ static int imx93_clocks_probe(struct platform_device *pdev) anatop_base = devm_of_iomap(dev, np, 0, NULL); of_node_put(np); if (WARN_ON(IS_ERR(anatop_base))) { - ret = PTR_ERR(base); + ret = PTR_ERR(anatop_base); goto unregister_hws; } -- cgit v1.2.3 From e7dd44f4f3166db45248414f5df8f615392de47a Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Fri, 7 Jul 2023 21:58:51 +0800 Subject: clk: fixed-mmio: make COMMON_CLK_FIXED_MMIO depend on HAS_IOMEM On s390 systems (aka mainframes), it has classic channel devices for networking and permanent storage that are currently even more common than PCI devices. Hence it could have a fully functional s390 kernel with CONFIG_PCI=n, then the relevant iomem mapping functions [including ioremap(), devm_ioremap(), etc.] are not available. Here let COMMON_CLK_FIXED_MMIO depend on HAS_IOMEM so that it won't be built to cause below compiling error if PCI is unset: ------ ld: drivers/clk/clk-fixed-mmio.o: in function `fixed_mmio_clk_setup': clk-fixed-mmio.c:(.text+0x5e): undefined reference to `of_iomap' ld: clk-fixed-mmio.c:(.text+0xba): undefined reference to `iounmap' ------ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306211329.ticOJCSv-lkp@intel.com/ Signed-off-by: Baoquan He Cc: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Link: https://lore.kernel.org/r/20230707135852.24292-8-bhe@redhat.com Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 93f38a8178ba..6b3b424addab 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -444,6 +444,7 @@ config COMMON_CLK_BD718XX config COMMON_CLK_FIXED_MMIO bool "Clock driver for Memory Mapped Fixed values" depends on COMMON_CLK && OF + depends on HAS_IOMEM help Support for Memory Mapped IO Fixed clocks -- cgit v1.2.3 From 8974eb588283b7d44a7c91fa09fcbaf380339f3a Mon Sep 17 00:00:00 2001 From: Daniel Sneddon Date: Wed, 12 Jul 2023 19:43:11 -0700 Subject: x86/speculation: Add Gather Data Sampling mitigation Gather Data Sampling (GDS) is a hardware vulnerability which allows unprivileged speculative access to data which was previously stored in vector registers. Intel processors that support AVX2 and AVX512 have gather instructions that fetch non-contiguous data elements from memory. On vulnerable hardware, when a gather instruction is transiently executed and encounters a fault, stale data from architectural or internal vector registers may get transiently stored to the destination vector register allowing an attacker to infer the stale data using typical side channel techniques like cache timing attacks. This mitigation is different from many earlier ones for two reasons. First, it is enabled by default and a bit must be set to *DISABLE* it. This is the opposite of normal mitigation polarity. This means GDS can be mitigated simply by updating microcode and leaving the new control bit alone. Second, GDS has a "lock" bit. This lock bit is there because the mitigation affects the hardware security features KeyLocker and SGX. It needs to be enabled and *STAY* enabled for these features to be mitigated against GDS. The mitigation is enabled in the microcode by default. Disable it by setting gather_data_sampling=off or by disabling all mitigations with mitigations=off. The mitigation status can be checked by reading: /sys/devices/system/cpu/vulnerabilities/gather_data_sampling Signed-off-by: Daniel Sneddon Signed-off-by: Dave Hansen Acked-by: Josh Poimboeuf --- Documentation/ABI/testing/sysfs-devices-system-cpu | 13 ++- .../admin-guide/hw-vuln/gather_data_sampling.rst | 99 ++++++++++++++++ Documentation/admin-guide/hw-vuln/index.rst | 1 + Documentation/admin-guide/kernel-parameters.txt | 41 ++++--- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/msr-index.h | 11 ++ arch/x86/kernel/cpu/bugs.c | 129 +++++++++++++++++++++ arch/x86/kernel/cpu/common.c | 34 ++++-- arch/x86/kernel/cpu/cpu.h | 1 + drivers/base/cpu.c | 8 ++ 10 files changed, 310 insertions(+), 28 deletions(-) create mode 100644 Documentation/admin-guide/hw-vuln/gather_data_sampling.rst diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index ecd585ca2d50..77942eedf4f6 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -513,17 +513,18 @@ Description: information about CPUs heterogeneity. cpu_capacity: capacity of cpuX. What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/gather_data_sampling + /sys/devices/system/cpu/vulnerabilities/itlb_multihit + /sys/devices/system/cpu/vulnerabilities/l1tf + /sys/devices/system/cpu/vulnerabilities/mds /sys/devices/system/cpu/vulnerabilities/meltdown + /sys/devices/system/cpu/vulnerabilities/mmio_stale_data + /sys/devices/system/cpu/vulnerabilities/retbleed + /sys/devices/system/cpu/vulnerabilities/spec_store_bypass /sys/devices/system/cpu/vulnerabilities/spectre_v1 /sys/devices/system/cpu/vulnerabilities/spectre_v2 - /sys/devices/system/cpu/vulnerabilities/spec_store_bypass - /sys/devices/system/cpu/vulnerabilities/l1tf - /sys/devices/system/cpu/vulnerabilities/mds /sys/devices/system/cpu/vulnerabilities/srbds /sys/devices/system/cpu/vulnerabilities/tsx_async_abort - /sys/devices/system/cpu/vulnerabilities/itlb_multihit - /sys/devices/system/cpu/vulnerabilities/mmio_stale_data - /sys/devices/system/cpu/vulnerabilities/retbleed Date: January 2018 Contact: Linux kernel mailing list Description: Information about CPU vulnerabilities diff --git a/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst new file mode 100644 index 000000000000..74dab6af7fe1 --- /dev/null +++ b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst @@ -0,0 +1,99 @@ +.. SPDX-License-Identifier: GPL-2.0 + +GDS - Gather Data Sampling +========================== + +Gather Data Sampling is a hardware vulnerability which allows unprivileged +speculative access to data which was previously stored in vector registers. + +Problem +------- +When a gather instruction performs loads from memory, different data elements +are merged into the destination vector register. However, when a gather +instruction that is transiently executed encounters a fault, stale data from +architectural or internal vector registers may get transiently forwarded to the +destination vector register instead. This will allow a malicious attacker to +infer stale data using typical side channel techniques like cache timing +attacks. GDS is a purely sampling-based attack. + +The attacker uses gather instructions to infer the stale vector register data. +The victim does not need to do anything special other than use the vector +registers. The victim does not need to use gather instructions to be +vulnerable. + +Because the buffers are shared between Hyper-Threads cross Hyper-Thread attacks +are possible. + +Attack scenarios +---------------- +Without mitigation, GDS can infer stale data across virtually all +permission boundaries: + + Non-enclaves can infer SGX enclave data + Userspace can infer kernel data + Guests can infer data from hosts + Guest can infer guest from other guests + Users can infer data from other users + +Because of this, it is important to ensure that the mitigation stays enabled in +lower-privilege contexts like guests and when running outside SGX enclaves. + +The hardware enforces the mitigation for SGX. Likewise, VMMs should ensure +that guests are not allowed to disable the GDS mitigation. If a host erred and +allowed this, a guest could theoretically disable GDS mitigation, mount an +attack, and re-enable it. + +Mitigation mechanism +-------------------- +This issue is mitigated in microcode. The microcode defines the following new +bits: + + ================================ === ============================ + IA32_ARCH_CAPABILITIES[GDS_CTRL] R/O Enumerates GDS vulnerability + and mitigation support. + IA32_ARCH_CAPABILITIES[GDS_NO] R/O Processor is not vulnerable. + IA32_MCU_OPT_CTRL[GDS_MITG_DIS] R/W Disables the mitigation + 0 by default. + IA32_MCU_OPT_CTRL[GDS_MITG_LOCK] R/W Locks GDS_MITG_DIS=0. Writes + to GDS_MITG_DIS are ignored + Can't be cleared once set. + ================================ === ============================ + +GDS can also be mitigated on systems that don't have updated microcode by +disabling AVX. This can be done by setting "clearcpuid=avx" on the kernel +command-line. + +Mitigation control on the kernel command line +--------------------------------------------- +The mitigation can be disabled by setting "gather_data_sampling=off" or +"mitigations=off" on the kernel command line. Not specifying either will +default to the mitigation being enabled. + +GDS System Information +------------------------ +The kernel provides vulnerability status information through sysfs. For +GDS this can be accessed by the following sysfs file: + +/sys/devices/system/cpu/vulnerabilities/gather_data_sampling + +The possible values contained in this file are: + + ============================== ============================================= + Not affected Processor not vulnerable. + Vulnerable Processor vulnerable and mitigation disabled. + Vulnerable: No microcode Processor vulnerable and microcode is missing + mitigation. + Mitigation: Microcode Processor is vulnerable and mitigation is in + effect. + Mitigation: Microcode (locked) Processor is vulnerable and mitigation is in + effect and cannot be disabled. + Unknown: Dependent on + hypervisor status Running on a virtual guest processor that is + affected but with no way to know if host + processor is mitigated or vulnerable. + ============================== ============================================= + +GDS Default mitigation +---------------------- +The updated microcode will enable the mitigation by default. The kernel's +default action is to leave the mitigation enabled. diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst index e0614760a99e..436fac0bd9c3 100644 --- a/Documentation/admin-guide/hw-vuln/index.rst +++ b/Documentation/admin-guide/hw-vuln/index.rst @@ -19,3 +19,4 @@ are configurable at compile, boot or run time. l1d_flush.rst processor_mmio_stale_data.rst cross-thread-rsb.rst + gather_data_sampling.rst diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a1457995fd41..c21d42140d6b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1623,6 +1623,20 @@ Format: off | on default: on + gather_data_sampling= + [X86,INTEL] Control the Gather Data Sampling (GDS) + mitigation. + + Gather Data Sampling is a hardware vulnerability which + allows unprivileged speculative access to data which was + previously stored in vector registers. + + This issue is mitigated by default in updated microcode. + The mitigation may have a performance impact but can be + disabled. + + off: Disable GDS mitigation. + gcov_persist= [GCOV] When non-zero (default), profiling data for kernel modules is saved and remains accessible via debugfs, even when the module is unloaded/reloaded. @@ -3273,24 +3287,25 @@ Disable all optional CPU mitigations. This improves system performance, but it may also expose users to several CPU vulnerabilities. - Equivalent to: nopti [X86,PPC] - if nokaslr then kpti=0 [ARM64] - nospectre_v1 [X86,PPC] - nobp=0 [S390] - nospectre_v2 [X86,PPC,S390,ARM64] - spectre_v2_user=off [X86] - spec_store_bypass_disable=off [X86,PPC] - ssbd=force-off [ARM64] - nospectre_bhb [ARM64] + Equivalent to: if nokaslr then kpti=0 [ARM64] + gather_data_sampling=off [X86] + kvm.nx_huge_pages=off [X86] l1tf=off [X86] mds=off [X86] - tsx_async_abort=off [X86] - kvm.nx_huge_pages=off [X86] - srbds=off [X86,INTEL] + mmio_stale_data=off [X86] no_entry_flush [PPC] no_uaccess_flush [PPC] - mmio_stale_data=off [X86] + nobp=0 [S390] + nopti [X86,PPC] + nospectre_bhb [ARM64] + nospectre_v1 [X86,PPC] + nospectre_v2 [X86,PPC,S390,ARM64] retbleed=off [X86] + spec_store_bypass_disable=off [X86,PPC] + spectre_v2_user=off [X86] + srbds=off [X86,INTEL] + ssbd=force-off [ARM64] + tsx_async_abort=off [X86] Exceptions: This does not have any effect on diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index cb8ca46213be..8d6b34726033 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -483,5 +483,6 @@ #define X86_BUG_RETBLEED X86_BUG(27) /* CPU is affected by RETBleed */ #define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */ #define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */ +#define X86_BUG_GDS X86_BUG(30) /* CPU is affected by Gather Data Sampling */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3aedae61af4f..348f3da8b0f6 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -155,6 +155,15 @@ * Not susceptible to Post-Barrier * Return Stack Buffer Predictions. */ +#define ARCH_CAP_GDS_CTRL BIT(25) /* + * CPU is vulnerable to Gather + * Data Sampling (GDS) and + * has controls for mitigation. + */ +#define ARCH_CAP_GDS_NO BIT(26) /* + * CPU is not vulnerable to Gather + * Data Sampling (GDS). + */ #define ARCH_CAP_XAPIC_DISABLE BIT(21) /* * IA32_XAPIC_DISABLE_STATUS MSR @@ -178,6 +187,8 @@ #define RNGDS_MITG_DIS BIT(0) /* SRBDS support */ #define RTM_ALLOW BIT(1) /* TSX development mode */ #define FB_CLEAR_DIS BIT(3) /* CPU Fill buffer clear disable */ +#define GDS_MITG_DIS BIT(4) /* Disable GDS mitigation */ +#define GDS_MITG_LOCKED BIT(5) /* GDS mitigation locked */ #define MSR_IA32_SYSENTER_CS 0x00000174 #define MSR_IA32_SYSENTER_ESP 0x00000175 diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 9e2a91830f72..7824b101ddfe 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -47,6 +47,7 @@ static void __init taa_select_mitigation(void); static void __init mmio_select_mitigation(void); static void __init srbds_select_mitigation(void); static void __init l1d_flush_select_mitigation(void); +static void __init gds_select_mitigation(void); /* The base value of the SPEC_CTRL MSR without task-specific bits set */ u64 x86_spec_ctrl_base; @@ -160,6 +161,7 @@ void __init cpu_select_mitigations(void) md_clear_select_mitigation(); srbds_select_mitigation(); l1d_flush_select_mitigation(); + gds_select_mitigation(); } /* @@ -645,6 +647,120 @@ static int __init l1d_flush_parse_cmdline(char *str) } early_param("l1d_flush", l1d_flush_parse_cmdline); +#undef pr_fmt +#define pr_fmt(fmt) "GDS: " fmt + +enum gds_mitigations { + GDS_MITIGATION_OFF, + GDS_MITIGATION_UCODE_NEEDED, + GDS_MITIGATION_FULL, + GDS_MITIGATION_FULL_LOCKED, + GDS_MITIGATION_HYPERVISOR, +}; + +static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL; + +static const char * const gds_strings[] = { + [GDS_MITIGATION_OFF] = "Vulnerable", + [GDS_MITIGATION_UCODE_NEEDED] = "Vulnerable: No microcode", + [GDS_MITIGATION_FULL] = "Mitigation: Microcode", + [GDS_MITIGATION_FULL_LOCKED] = "Mitigation: Microcode (locked)", + [GDS_MITIGATION_HYPERVISOR] = "Unknown: Dependent on hypervisor status", +}; + +void update_gds_msr(void) +{ + u64 mcu_ctrl_after; + u64 mcu_ctrl; + + switch (gds_mitigation) { + case GDS_MITIGATION_OFF: + rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); + mcu_ctrl |= GDS_MITG_DIS; + break; + case GDS_MITIGATION_FULL_LOCKED: + /* + * The LOCKED state comes from the boot CPU. APs might not have + * the same state. Make sure the mitigation is enabled on all + * CPUs. + */ + case GDS_MITIGATION_FULL: + rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); + mcu_ctrl &= ~GDS_MITG_DIS; + break; + case GDS_MITIGATION_UCODE_NEEDED: + case GDS_MITIGATION_HYPERVISOR: + return; + }; + + wrmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); + + /* + * Check to make sure that the WRMSR value was not ignored. Writes to + * GDS_MITG_DIS will be ignored if this processor is locked but the boot + * processor was not. + */ + rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl_after); + WARN_ON_ONCE(mcu_ctrl != mcu_ctrl_after); +} + +static void __init gds_select_mitigation(void) +{ + u64 mcu_ctrl; + + if (!boot_cpu_has_bug(X86_BUG_GDS)) + return; + + if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) { + gds_mitigation = GDS_MITIGATION_HYPERVISOR; + goto out; + } + + if (cpu_mitigations_off()) + gds_mitigation = GDS_MITIGATION_OFF; + /* Will verify below that mitigation _can_ be disabled */ + + /* No microcode */ + if (!(x86_read_arch_cap_msr() & ARCH_CAP_GDS_CTRL)) { + gds_mitigation = GDS_MITIGATION_UCODE_NEEDED; + goto out; + } + + rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); + if (mcu_ctrl & GDS_MITG_LOCKED) { + if (gds_mitigation == GDS_MITIGATION_OFF) + pr_warn("Mitigation locked. Disable failed.\n"); + + /* + * The mitigation is selected from the boot CPU. All other CPUs + * _should_ have the same state. If the boot CPU isn't locked + * but others are then update_gds_msr() will WARN() of the state + * mismatch. If the boot CPU is locked update_gds_msr() will + * ensure the other CPUs have the mitigation enabled. + */ + gds_mitigation = GDS_MITIGATION_FULL_LOCKED; + } + + update_gds_msr(); +out: + pr_info("%s\n", gds_strings[gds_mitigation]); +} + +static int __init gds_parse_cmdline(char *str) +{ + if (!str) + return -EINVAL; + + if (!boot_cpu_has_bug(X86_BUG_GDS)) + return 0; + + if (!strcmp(str, "off")) + gds_mitigation = GDS_MITIGATION_OFF; + + return 0; +} +early_param("gather_data_sampling", gds_parse_cmdline); + #undef pr_fmt #define pr_fmt(fmt) "Spectre V1 : " fmt @@ -2382,6 +2498,11 @@ static ssize_t retbleed_show_state(char *buf) return sysfs_emit(buf, "%s\n", retbleed_strings[retbleed_mitigation]); } +static ssize_t gds_show_state(char *buf) +{ + return sysfs_emit(buf, "%s\n", gds_strings[gds_mitigation]); +} + static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, char *buf, unsigned int bug) { @@ -2431,6 +2552,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr case X86_BUG_RETBLEED: return retbleed_show_state(buf); + case X86_BUG_GDS: + return gds_show_state(buf); + default: break; } @@ -2495,4 +2619,9 @@ ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, cha { return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED); } + +ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *buf) +{ + return cpu_show_common(dev, attr, buf, X86_BUG_GDS); +} #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 52683fddafaf..53224fe3ca6f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1250,6 +1250,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { #define RETBLEED BIT(3) /* CPU is affected by SMT (cross-thread) return predictions */ #define SMT_RSB BIT(4) +/* CPU is affected by GDS */ +#define GDS BIT(5) static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS), @@ -1262,19 +1264,21 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_INTEL_STEPPINGS(BROADWELL_X, X86_STEPPING_ANY, MMIO), VULNBL_INTEL_STEPPINGS(BROADWELL, X86_STEPPING_ANY, SRBDS), VULNBL_INTEL_STEPPINGS(SKYLAKE_L, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), - VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED), + VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), VULNBL_INTEL_STEPPINGS(SKYLAKE, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), - VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), - VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED), + VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED | GDS), + VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, SRBDS | MMIO | RETBLEED | GDS), VULNBL_INTEL_STEPPINGS(CANNONLAKE_L, X86_STEPPING_ANY, RETBLEED), - VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), - VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO), - VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO), - VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), + VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), + VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS), + VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO | GDS), + VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPINGS(0x0, 0x0), MMIO | RETBLEED), - VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), + VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), + VULNBL_INTEL_STEPPINGS(TIGERLAKE_L, X86_STEPPING_ANY, GDS), + VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS), VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), - VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED), + VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS), VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO), VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS), @@ -1406,6 +1410,16 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) if (cpu_matches(cpu_vuln_blacklist, SMT_RSB)) setup_force_cpu_bug(X86_BUG_SMT_RSB); + /* + * Check if CPU is vulnerable to GDS. If running in a virtual machine on + * an affected processor, the VMM may have disabled the use of GATHER by + * disabling AVX2. The only way to do this in HW is to clear XCR0[2], + * which means that AVX will be disabled. + */ + if (cpu_matches(cpu_vuln_blacklist, GDS) && !(ia32_cap & ARCH_CAP_GDS_NO) && + boot_cpu_has(X86_FEATURE_AVX)) + setup_force_cpu_bug(X86_BUG_GDS); + if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) return; @@ -1962,6 +1976,8 @@ void identify_secondary_cpu(struct cpuinfo_x86 *c) validate_apic_and_package_id(c); x86_spec_ctrl_setup_ap(); update_srbds_msr(); + if (boot_cpu_has_bug(X86_BUG_GDS)) + update_gds_msr(); tsx_ap_init(); } diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index 1c44630d4789..1dcd7d4e38ef 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -83,6 +83,7 @@ void cpu_select_mitigations(void); extern void x86_spec_ctrl_setup_ap(void); extern void update_srbds_msr(void); +extern void update_gds_msr(void); extern enum spectre_v2_mitigation spectre_v2_enabled; diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c1815b9dae68..0469c09e8a8c 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -577,6 +577,12 @@ ssize_t __weak cpu_show_retbleed(struct device *dev, return sysfs_emit(buf, "Not affected\n"); } +ssize_t __weak cpu_show_gds(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); @@ -588,6 +594,7 @@ static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL); static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL); static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL); static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); +static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, @@ -601,6 +608,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_srbds.attr, &dev_attr_mmio_stale_data.attr, &dev_attr_retbleed.attr, + &dev_attr_gather_data_sampling.attr, NULL }; -- cgit v1.2.3 From d1ff11d7ad8704f8d615f6446041c221b2d2ec4d Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Wed, 19 Jul 2023 18:35:33 +0100 Subject: firmware: arm_scmi: Fix chan_free cleanup on SMC SCMI transport based on SMC can optionally use an additional IRQ to signal message completion. The associated interrupt handler is currently allocated using devres but on shutdown the core SCMI stack will call .chan_free() well before any managed cleanup is invoked by devres. As a consequence, the arrival of a late reply to an in-flight pending transaction could still trigger the interrupt handler well after the SCMI core has cleaned up the channels, with unpleasant results. Inhibit further message processing on the IRQ path by explicitly freeing the IRQ inside .chan_free() callback itself. Fixes: dd820ee21d5e ("firmware: arm_scmi: Augment SMC/HVC to allow optional interrupt") Reported-by: Bjorn Andersson Signed-off-by: Cristian Marussi Link: https://lore.kernel.org/r/20230719173533.2739319-1-cristian.marussi@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/smc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 2d8c510fbf52..c193516a254d 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -40,6 +40,7 @@ /** * struct scmi_smc - Structure representing a SCMI smc transport * + * @irq: An optional IRQ for completion * @cinfo: SCMI channel info * @shmem: Transmit/Receive shared memory area * @shmem_lock: Lock to protect access to Tx/Rx shared memory area. @@ -52,6 +53,7 @@ */ struct scmi_smc { + int irq; struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; /* Protect access to shmem area */ @@ -127,7 +129,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, struct resource res; struct device_node *np; u32 func_id; - int ret, irq; + int ret; if (!tx) return -ENODEV; @@ -169,11 +171,10 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, * completion of a message is signaled by an interrupt rather than by * the return of the SMC call. */ - irq = of_irq_get_byname(cdev->of_node, "a2p"); - if (irq > 0) { - ret = devm_request_irq(dev, irq, smc_msg_done_isr, - IRQF_NO_SUSPEND, - dev_name(dev), scmi_info); + scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p"); + if (scmi_info->irq > 0) { + ret = request_irq(scmi_info->irq, smc_msg_done_isr, + IRQF_NO_SUSPEND, dev_name(dev), scmi_info); if (ret) { dev_err(dev, "failed to setup SCMI smc irq\n"); return ret; @@ -195,6 +196,10 @@ static int smc_chan_free(int id, void *p, void *data) struct scmi_chan_info *cinfo = p; struct scmi_smc *scmi_info = cinfo->transport_info; + /* Ignore any possible further reception on the IRQ path */ + if (scmi_info->irq > 0) + free_irq(scmi_info->irq, scmi_info); + cinfo->transport_info = NULL; scmi_info->cinfo = NULL; -- cgit v1.2.3 From c718ca0e99401d80d2480c08e1b02cf5f7cd7033 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 19 Jul 2023 17:54:00 +0000 Subject: KVM: arm64: Fix hardware enable/disable flows for pKVM When running in protected mode, the hyp stub is disabled after pKVM is initialized, meaning the host cannot enable/disable the hyp at runtime. As such, kvm_arm_hardware_enabled is always 1 after initialization, and kvm_arch_hardware_enable() never enables the vgic maintenance irq or timer irqs. Unconditionally enable/disable the vgic + timer irqs in the respective calls, instead relying on the percpu bookkeeping in the generic code to keep track of which cpus have the interrupts unmasked. Fixes: 466d27e48d7c ("KVM: arm64: Simplify the CPUHP logic") Reported-by: Oliver Upton Suggested-by: Oliver Upton Signed-off-by: Raghavendra Rao Ananta Link: https://lore.kernel.org/r/20230719175400.647154-1-rananta@google.com Acked-by: Marc Zyngier Signed-off-by: Oliver Upton --- arch/arm64/kvm/arm.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 72dc53a75d1c..d8540563a623 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1874,8 +1874,6 @@ static void _kvm_arch_hardware_enable(void *discard) int kvm_arch_hardware_enable(void) { - int was_enabled; - /* * Most calls to this function are made with migration * disabled, but not with preemption disabled. The former is @@ -1884,13 +1882,10 @@ int kvm_arch_hardware_enable(void) */ preempt_disable(); - was_enabled = __this_cpu_read(kvm_arm_hardware_enabled); _kvm_arch_hardware_enable(NULL); - if (!was_enabled) { - kvm_vgic_cpu_up(); - kvm_timer_cpu_up(); - } + kvm_vgic_cpu_up(); + kvm_timer_cpu_up(); preempt_enable(); @@ -1907,10 +1902,8 @@ static void _kvm_arch_hardware_disable(void *discard) void kvm_arch_hardware_disable(void) { - if (__this_cpu_read(kvm_arm_hardware_enabled)) { - kvm_timer_cpu_down(); - kvm_vgic_cpu_down(); - } + kvm_timer_cpu_down(); + kvm_vgic_cpu_down(); if (!is_protected_kvm_enabled()) _kvm_arch_hardware_disable(NULL); -- cgit v1.2.3 From 733c758e509b86a5d38b9af927817258b88ededd Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 19 Jul 2023 23:18:55 +0000 Subject: KVM: arm64: Rephrase percpu enable/disable tracking in terms of hyp kvm_arm_hardware_enabled is rather misleading, since it doesn't track the state of all hardware resources needed for running a VM. What it actually tracks is whether or not the hyp cpu context has been initialized. Since we're now at the point where vgic + timer irq management has been separated from kvm_arm_hardware_enabled, rephrase it (and the associated helpers) to make it clear what state is being tracked. Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20230719231855.262973-1-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/arm.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index d8540563a623..d1cb298a58a0 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -55,7 +55,7 @@ DECLARE_KVM_NVHE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt); static bool vgic_present, kvm_arm_initialised; -static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled); +static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized); DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use); bool is_kvm_arm_initialised(void) @@ -1864,11 +1864,19 @@ static void cpu_hyp_reinit(void) cpu_hyp_init_features(); } -static void _kvm_arch_hardware_enable(void *discard) +static void cpu_hyp_init(void *discard) { - if (!__this_cpu_read(kvm_arm_hardware_enabled)) { + if (!__this_cpu_read(kvm_hyp_initialized)) { cpu_hyp_reinit(); - __this_cpu_write(kvm_arm_hardware_enabled, 1); + __this_cpu_write(kvm_hyp_initialized, 1); + } +} + +static void cpu_hyp_uninit(void *discard) +{ + if (__this_cpu_read(kvm_hyp_initialized)) { + cpu_hyp_reset(); + __this_cpu_write(kvm_hyp_initialized, 0); } } @@ -1882,7 +1890,7 @@ int kvm_arch_hardware_enable(void) */ preempt_disable(); - _kvm_arch_hardware_enable(NULL); + cpu_hyp_init(NULL); kvm_vgic_cpu_up(); kvm_timer_cpu_up(); @@ -1892,21 +1900,13 @@ int kvm_arch_hardware_enable(void) return 0; } -static void _kvm_arch_hardware_disable(void *discard) -{ - if (__this_cpu_read(kvm_arm_hardware_enabled)) { - cpu_hyp_reset(); - __this_cpu_write(kvm_arm_hardware_enabled, 0); - } -} - void kvm_arch_hardware_disable(void) { kvm_timer_cpu_down(); kvm_vgic_cpu_down(); if (!is_protected_kvm_enabled()) - _kvm_arch_hardware_disable(NULL); + cpu_hyp_uninit(NULL); } #ifdef CONFIG_CPU_PM @@ -1915,16 +1915,16 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self, void *v) { /* - * kvm_arm_hardware_enabled is left with its old value over + * kvm_hyp_initialized is left with its old value over * PM_ENTER->PM_EXIT. It is used to indicate PM_EXIT should * re-enable hyp. */ switch (cmd) { case CPU_PM_ENTER: - if (__this_cpu_read(kvm_arm_hardware_enabled)) + if (__this_cpu_read(kvm_hyp_initialized)) /* - * don't update kvm_arm_hardware_enabled here - * so that the hardware will be re-enabled + * don't update kvm_hyp_initialized here + * so that the hyp will be re-enabled * when we resume. See below. */ cpu_hyp_reset(); @@ -1932,8 +1932,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self, return NOTIFY_OK; case CPU_PM_ENTER_FAILED: case CPU_PM_EXIT: - if (__this_cpu_read(kvm_arm_hardware_enabled)) - /* The hardware was enabled before suspend. */ + if (__this_cpu_read(kvm_hyp_initialized)) + /* The hyp was enabled before suspend. */ cpu_hyp_reinit(); return NOTIFY_OK; @@ -2014,7 +2014,7 @@ static int __init init_subsystems(void) /* * Enable hardware so that subsystem initialisation can access EL2. */ - on_each_cpu(_kvm_arch_hardware_enable, NULL, 1); + on_each_cpu(cpu_hyp_init, NULL, 1); /* * Register CPU lower-power notifier @@ -2052,7 +2052,7 @@ out: hyp_cpu_pm_exit(); if (err || !is_protected_kvm_enabled()) - on_each_cpu(_kvm_arch_hardware_disable, NULL, 1); + on_each_cpu(cpu_hyp_uninit, NULL, 1); return err; } @@ -2090,7 +2090,7 @@ static int __init do_pkvm_init(u32 hyp_va_bits) * The stub hypercalls are now disabled, so set our local flag to * prevent a later re-init attempt in kvm_arch_hardware_enable(). */ - __this_cpu_write(kvm_arm_hardware_enabled, 1); + __this_cpu_write(kvm_hyp_initialized, 1); preempt_enable(); return ret; -- cgit v1.2.3 From 272ffb925e2020000863748867d91a2407d3e8e9 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 20 Jun 2023 13:01:59 -0400 Subject: counter: Fix menuconfig "Counter support" submenu entries disappearance The current placement of the I8254 Kconfig entry results in the disappearance of the "Counter support" submenu items in menuconfig. Move the I8254 above the menuconfig COUNTER entry to restore the intended submenu behavior. Fixes: d428487471ba ("counter: i8254: Introduce the Intel 8254 interface library module") Reported-by: Jarkko Nikula Closes: https://lore.kernel.org/all/32ddaa7b-53a8-d61f-d526-b545bd561337@linux.intel.com/ Reviewed-by: Randy Dunlap Tested-by: Jarkko Nikula Reviewed-by: Jarkko Nikula Link: https://lore.kernel.org/r/20230620170159.556788-1-william.gray@linaro.org/ Signed-off-by: William Breathitt Gray --- drivers/counter/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index bca21df51168..62962ae84b77 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -3,13 +3,6 @@ # Counter devices # -menuconfig COUNTER - tristate "Counter support" - help - This enables counter device support through the Generic Counter - interface. You only need to enable this, if you also want to enable - one or more of the counter device drivers below. - config I8254 tristate select COUNTER @@ -25,6 +18,13 @@ config I8254 If built as a module its name will be i8254. +menuconfig COUNTER + tristate "Counter support" + help + This enables counter device support through the Generic Counter + interface. You only need to enable this, if you also want to enable + one or more of the counter device drivers below. + if COUNTER config 104_QUAD_8 -- cgit v1.2.3 From 1b95e817916069ec45a7f259d088fd1c091a8cc6 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 11 Jul 2023 17:40:39 +0800 Subject: nvme: fix possible hang when removing a controller during error recovery Error recovery can be interrupted by controller removal, then the controller is left as quiesced, and IO hang can be caused. Fix the issue by unquiescing controller unconditionally when removing namespaces. This way is reasonable and safe given forward progress can be made when removing namespaces. Reviewed-by: Keith Busch Reviewed-by: Sagi Grimberg Reported-by: Chunguang Xu Closes: https://lore.kernel.org/linux-nvme/cover.1685350577.git.chunguang.xu@shopee.com/ Cc: stable@vger.kernel.org Signed-off-by: Ming Lei Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 37b6fa746662..f3a01b79148c 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3933,6 +3933,12 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) */ nvme_mpath_clear_ctrl_paths(ctrl); + /* + * Unquiesce io queues so any pending IO won't hang, especially + * those submitted from scan work + */ + nvme_unquiesce_io_queues(ctrl); + /* prevent racing with ns scanning */ flush_work(&ctrl->scan_work); @@ -3942,10 +3948,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) * removing the namespaces' disks; fail all the queues now to avoid * potentially having to clean up the failed sync later. */ - if (ctrl->state == NVME_CTRL_DEAD) { + if (ctrl->state == NVME_CTRL_DEAD) nvme_mark_namespaces_dead(ctrl); - nvme_unquiesce_io_queues(ctrl); - } /* this is a no-op when called from the controller reset handler */ nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING_NOIO); -- cgit v1.2.3 From 99dc264014d5aed66ee37ddf136a38b5a2b1b529 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 11 Jul 2023 17:40:40 +0800 Subject: nvme-tcp: fix potential unbalanced freeze & unfreeze Move start_freeze into nvme_tcp_configure_io_queues(), and there is at least two benefits: 1) fix unbalanced freeze and unfreeze, since re-connection work may fail or be broken by removal 2) IO during error recovery can be failfast quickly because nvme fabrics unquiesces queues after teardown. One side-effect is that !mpath request may timeout during connecting because of queue topo change, but that looks not one big deal: 1) same problem exists with current code base 2) compared with !mpath, mpath use case is dominant Fixes: 2875b0aecabe ("nvme-tcp: fix controller reset hang during traffic") Cc: stable@vger.kernel.org Signed-off-by: Ming Lei Tested-by: Yi Zhang Reviewed-by: Sagi Grimberg Signed-off-by: Keith Busch --- drivers/nvme/host/tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 3e7dd6f91832..fb24cd8ac46c 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1868,6 +1868,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) goto out_cleanup_connect_q; if (!new) { + nvme_start_freeze(ctrl); nvme_unquiesce_io_queues(ctrl); if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) { /* @@ -1876,6 +1877,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) * to be safe. */ ret = -ENODEV; + nvme_unfreeze(ctrl); goto out_wait_freeze_timed_out; } blk_mq_update_nr_hw_queues(ctrl->tagset, @@ -1980,7 +1982,6 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl, if (ctrl->queue_count <= 1) return; nvme_quiesce_admin_queue(ctrl); - nvme_start_freeze(ctrl); nvme_quiesce_io_queues(ctrl); nvme_sync_io_queues(ctrl); nvme_tcp_stop_io_queues(ctrl); -- cgit v1.2.3 From 29b434d1e49252b3ad56ad3197e47fafff5356a1 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 11 Jul 2023 17:40:41 +0800 Subject: nvme-rdma: fix potential unbalanced freeze & unfreeze Move start_freeze into nvme_rdma_configure_io_queues(), and there is at least two benefits: 1) fix unbalanced freeze and unfreeze, since re-connection work may fail or be broken by removal 2) IO during error recovery can be failfast quickly because nvme fabrics unquiesces queues after teardown. One side-effect is that !mpath request may timeout during connecting because of queue topo change, but that looks not one big deal: 1) same problem exists with current code base 2) compared with !mpath, mpath use case is dominant Fixes: 9f98772ba307 ("nvme-rdma: fix controller reset hang during traffic") Cc: stable@vger.kernel.org Signed-off-by: Ming Lei Tested-by: Yi Zhang Reviewed-by: Sagi Grimberg Signed-off-by: Keith Busch --- drivers/nvme/host/rdma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index d433b2ec07a6..337a624a537c 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -883,6 +883,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new) goto out_cleanup_tagset; if (!new) { + nvme_start_freeze(&ctrl->ctrl); nvme_unquiesce_io_queues(&ctrl->ctrl); if (!nvme_wait_freeze_timeout(&ctrl->ctrl, NVME_IO_TIMEOUT)) { /* @@ -891,6 +892,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new) * to be safe. */ ret = -ENODEV; + nvme_unfreeze(&ctrl->ctrl); goto out_wait_freeze_timed_out; } blk_mq_update_nr_hw_queues(ctrl->ctrl.tagset, @@ -940,7 +942,6 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl, bool remove) { if (ctrl->ctrl.queue_count > 1) { - nvme_start_freeze(&ctrl->ctrl); nvme_quiesce_io_queues(&ctrl->ctrl); nvme_sync_io_queues(&ctrl->ctrl); nvme_rdma_stop_io_queues(ctrl); -- cgit v1.2.3 From b44c11d86b7a170e657030cbd4ff6067e233e8fb Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 11 Jul 2023 10:26:17 +0100 Subject: ARM: dts: nspire: Fix arm primecell compatible string Commit c44e0503e5fd ("docs: dt: fix documented Primecell compatible string") removed the last occurrence of incorrect "arm,amba-primecell" compatible string, but somehow one occurrence of the same is left in the nspire platform. Fix the same by replacing it with the correct "arm,primecell" compatible. Cc: Rob Herring Cc: Krzysztof Kozlowski Cc: Conor Dooley Cc: devicetree@vger.kernel.org Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20230711092617.1412815-1-sudeep.holla@arm.com Signed-off-by: Arnd Bergmann --- arch/arm/boot/dts/nspire/nspire.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nspire/nspire.dtsi b/arch/arm/boot/dts/nspire/nspire.dtsi index bb240e6a3a6f..088bcc38589f 100644 --- a/arch/arm/boot/dts/nspire/nspire.dtsi +++ b/arch/arm/boot/dts/nspire/nspire.dtsi @@ -161,7 +161,7 @@ }; watchdog: watchdog@90060000 { - compatible = "arm,amba-primecell"; + compatible = "arm,primecell"; reg = <0x90060000 0x1000>; interrupts = <3>; }; -- cgit v1.2.3 From f6ad3c13f1b8c4e785cb7bd423887197142f47b0 Mon Sep 17 00:00:00 2001 From: Durai Manickam KR Date: Wed, 12 Jul 2023 15:30:42 +0530 Subject: ARM: dts: at91: sam9x60: fix the SOC detection Remove the dbgu compatible strings in the UART submodule of the flexcom for the proper SOC detection. Fixes: 99c808335877 (ARM: dts: at91: sam9x60: Add missing flexcom definitions) Signed-off-by: Durai Manickam KR Link: https://lore.kernel.org/r/20230712100042.317856-1-durai.manickamkr@microchip.com Signed-off-by: Arnd Bergmann --- arch/arm/boot/dts/microchip/sam9x60.dtsi | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/microchip/sam9x60.dtsi b/arch/arm/boot/dts/microchip/sam9x60.dtsi index 8b53997675e7..73d570a17269 100644 --- a/arch/arm/boot/dts/microchip/sam9x60.dtsi +++ b/arch/arm/boot/dts/microchip/sam9x60.dtsi @@ -172,7 +172,7 @@ status = "disabled"; uart4: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <13 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -240,7 +240,7 @@ status = "disabled"; uart5: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; atmel,usart-mode = ; interrupts = <14 IRQ_TYPE_LEVEL_HIGH 7>; @@ -370,7 +370,7 @@ status = "disabled"; uart11: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <32 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -419,7 +419,7 @@ status = "disabled"; uart12: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <33 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -576,7 +576,7 @@ status = "disabled"; uart6: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <9 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -625,7 +625,7 @@ status = "disabled"; uart7: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <10 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -674,7 +674,7 @@ status = "disabled"; uart8: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <11 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -723,7 +723,7 @@ status = "disabled"; uart0: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <5 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -791,7 +791,7 @@ status = "disabled"; uart1: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <6 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -859,7 +859,7 @@ status = "disabled"; uart2: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <7 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -927,7 +927,7 @@ status = "disabled"; uart3: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <8 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -1050,7 +1050,7 @@ status = "disabled"; uart9: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <15 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 @@ -1099,7 +1099,7 @@ status = "disabled"; uart10: serial@200 { - compatible = "microchip,sam9x60-dbgu", "microchip,sam9x60-usart", "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"; + compatible = "microchip,sam9x60-usart", "atmel,at91sam9260-usart"; reg = <0x200 0x200>; interrupts = <16 IRQ_TYPE_LEVEL_HIGH 7>; dmas = <&dma0 -- cgit v1.2.3 From 553a5c03e90a6087e88f8ff878335ef0621536fb Mon Sep 17 00:00:00 2001 From: Daniel Sneddon Date: Wed, 12 Jul 2023 19:43:12 -0700 Subject: x86/speculation: Add force option to GDS mitigation The Gather Data Sampling (GDS) vulnerability allows malicious software to infer stale data previously stored in vector registers. This may include sensitive data such as cryptographic keys. GDS is mitigated in microcode, and systems with up-to-date microcode are protected by default. However, any affected system that is running with older microcode will still be vulnerable to GDS attacks. Since the gather instructions used by the attacker are part of the AVX2 and AVX512 extensions, disabling these extensions prevents gather instructions from being executed, thereby mitigating the system from GDS. Disabling AVX2 is sufficient, but we don't have the granularity to do this. The XCR0[2] disables AVX, with no option to just disable AVX2. Add a kernel parameter gather_data_sampling=force that will enable the microcode mitigation if available, otherwise it will disable AVX on affected systems. This option will be ignored if cmdline mitigations=off. This is a *big* hammer. It is known to break buggy userspace that uses incomplete, buggy AVX enumeration. Unfortunately, such userspace does exist in the wild: https://www.mail-archive.com/bug-coreutils@gnu.org/msg33046.html [ dhansen: add some more ominous warnings about disabling AVX ] Signed-off-by: Daniel Sneddon Signed-off-by: Dave Hansen Acked-by: Josh Poimboeuf --- .../admin-guide/hw-vuln/gather_data_sampling.rst | 18 ++++++++++++++---- Documentation/admin-guide/kernel-parameters.txt | 8 +++++++- arch/x86/kernel/cpu/bugs.c | 20 +++++++++++++++++++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst index 74dab6af7fe1..40b7a6260010 100644 --- a/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst +++ b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst @@ -60,14 +60,21 @@ bits: ================================ === ============================ GDS can also be mitigated on systems that don't have updated microcode by -disabling AVX. This can be done by setting "clearcpuid=avx" on the kernel -command-line. +disabling AVX. This can be done by setting gather_data_sampling="force" or +"clearcpuid=avx" on the kernel command-line. + +If used, these options will disable AVX use by turning on XSAVE YMM support. +However, the processor will still enumerate AVX support. Userspace that +does not follow proper AVX enumeration to check both AVX *and* XSAVE YMM +support will break. Mitigation control on the kernel command line --------------------------------------------- The mitigation can be disabled by setting "gather_data_sampling=off" or -"mitigations=off" on the kernel command line. Not specifying either will -default to the mitigation being enabled. +"mitigations=off" on the kernel command line. Not specifying either will default +to the mitigation being enabled. Specifying "gather_data_sampling=force" will +use the microcode mitigation when available or disable AVX on affected systems +where the microcode hasn't been updated to include the mitigation. GDS System Information ------------------------ @@ -83,6 +90,9 @@ The possible values contained in this file are: Vulnerable Processor vulnerable and mitigation disabled. Vulnerable: No microcode Processor vulnerable and microcode is missing mitigation. + Mitigation: AVX disabled, + no microcode Processor is vulnerable and microcode is missing + mitigation. AVX disabled as mitigation. Mitigation: Microcode Processor is vulnerable and mitigation is in effect. Mitigation: Microcode (locked) Processor is vulnerable and mitigation is in diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index c21d42140d6b..816b966bed0f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1633,7 +1633,13 @@ This issue is mitigated by default in updated microcode. The mitigation may have a performance impact but can be - disabled. + disabled. On systems without the microcode mitigation + disabling AVX serves as a mitigation. + + force: Disable AVX to mitigate systems without + microcode mitigation. No effect if the microcode + mitigation is present. Known to cause crashes in + userspace with buggy AVX enumeration. off: Disable GDS mitigation. diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 7824b101ddfe..155e8d1c325e 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -653,6 +653,7 @@ early_param("l1d_flush", l1d_flush_parse_cmdline); enum gds_mitigations { GDS_MITIGATION_OFF, GDS_MITIGATION_UCODE_NEEDED, + GDS_MITIGATION_FORCE, GDS_MITIGATION_FULL, GDS_MITIGATION_FULL_LOCKED, GDS_MITIGATION_HYPERVISOR, @@ -663,6 +664,7 @@ static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL static const char * const gds_strings[] = { [GDS_MITIGATION_OFF] = "Vulnerable", [GDS_MITIGATION_UCODE_NEEDED] = "Vulnerable: No microcode", + [GDS_MITIGATION_FORCE] = "Mitigation: AVX disabled, no microcode", [GDS_MITIGATION_FULL] = "Mitigation: Microcode", [GDS_MITIGATION_FULL_LOCKED] = "Mitigation: Microcode (locked)", [GDS_MITIGATION_HYPERVISOR] = "Unknown: Dependent on hypervisor status", @@ -688,6 +690,7 @@ void update_gds_msr(void) rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); mcu_ctrl &= ~GDS_MITG_DIS; break; + case GDS_MITIGATION_FORCE: case GDS_MITIGATION_UCODE_NEEDED: case GDS_MITIGATION_HYPERVISOR: return; @@ -722,10 +725,23 @@ static void __init gds_select_mitigation(void) /* No microcode */ if (!(x86_read_arch_cap_msr() & ARCH_CAP_GDS_CTRL)) { - gds_mitigation = GDS_MITIGATION_UCODE_NEEDED; + if (gds_mitigation == GDS_MITIGATION_FORCE) { + /* + * This only needs to be done on the boot CPU so do it + * here rather than in update_gds_msr() + */ + setup_clear_cpu_cap(X86_FEATURE_AVX); + pr_warn("Microcode update needed! Disabling AVX as mitigation.\n"); + } else { + gds_mitigation = GDS_MITIGATION_UCODE_NEEDED; + } goto out; } + /* Microcode has mitigation, use it */ + if (gds_mitigation == GDS_MITIGATION_FORCE) + gds_mitigation = GDS_MITIGATION_FULL; + rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_ctrl); if (mcu_ctrl & GDS_MITG_LOCKED) { if (gds_mitigation == GDS_MITIGATION_OFF) @@ -756,6 +772,8 @@ static int __init gds_parse_cmdline(char *str) if (!strcmp(str, "off")) gds_mitigation = GDS_MITIGATION_OFF; + else if (!strcmp(str, "force")) + gds_mitigation = GDS_MITIGATION_FORCE; return 0; } -- cgit v1.2.3 From 53cf5797f114ba2bd86d23a862302119848eff19 Mon Sep 17 00:00:00 2001 From: Daniel Sneddon Date: Wed, 12 Jul 2023 19:43:13 -0700 Subject: x86/speculation: Add Kconfig option for GDS Gather Data Sampling (GDS) is mitigated in microcode. However, on systems that haven't received the updated microcode, disabling AVX can act as a mitigation. Add a Kconfig option that uses the microcode mitigation if available and disables AVX otherwise. Setting this option has no effect on systems not affected by GDS. This is the equivalent of setting gather_data_sampling=force. Signed-off-by: Daniel Sneddon Signed-off-by: Dave Hansen Acked-by: Josh Poimboeuf --- arch/x86/Kconfig | 19 +++++++++++++++++++ arch/x86/kernel/cpu/bugs.c | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7422db409770..36d3f61c4ed9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2603,6 +2603,25 @@ config SLS against straight line speculation. The kernel image might be slightly larger. +config GDS_FORCE_MITIGATION + bool "Force GDS Mitigation" + depends on CPU_SUP_INTEL + default n + help + Gather Data Sampling (GDS) is a hardware vulnerability which allows + unprivileged speculative access to data which was previously stored in + vector registers. + + This option is equivalent to setting gather_data_sampling=force on the + command line. The microcode mitigation is used if present, otherwise + AVX is disabled as a mitigation. On affected systems that are missing + the microcode any userspace code that unconditionally uses AVX will + break with this option set. + + Setting this option on systems not vulnerable to GDS has no effect. + + If in doubt, say N. + endif config ARCH_HAS_ADD_PAGES diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 155e8d1c325e..41821a4551a2 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -659,7 +659,11 @@ enum gds_mitigations { GDS_MITIGATION_HYPERVISOR, }; +#if IS_ENABLED(CONFIG_GDS_FORCE_MITIGATION) +static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FORCE; +#else static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL; +#endif static const char * const gds_strings[] = { [GDS_MITIGATION_OFF] = "Vulnerable", -- cgit v1.2.3 From 81ac7e5d741742d650b4ed6186c4826c1a0631a7 Mon Sep 17 00:00:00 2001 From: Daniel Sneddon Date: Wed, 12 Jul 2023 19:43:14 -0700 Subject: KVM: Add GDS_NO support to KVM Gather Data Sampling (GDS) is a transient execution attack using gather instructions from the AVX2 and AVX512 extensions. This attack allows malicious code to infer data that was previously stored in vector registers. Systems that are not vulnerable to GDS will set the GDS_NO bit of the IA32_ARCH_CAPABILITIES MSR. This is useful for VM guests that may think they are on vulnerable systems that are, in fact, not affected. Guests that are running on affected hosts where the mitigation is enabled are protected as if they were running on an unaffected system. On all hosts that are not affected or that are mitigated, set the GDS_NO bit. Signed-off-by: Daniel Sneddon Signed-off-by: Dave Hansen Acked-by: Josh Poimboeuf --- arch/x86/kernel/cpu/bugs.c | 7 +++++++ arch/x86/kvm/x86.c | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 41821a4551a2..7985c658d129 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -674,6 +674,13 @@ static const char * const gds_strings[] = { [GDS_MITIGATION_HYPERVISOR] = "Unknown: Dependent on hypervisor status", }; +bool gds_ucode_mitigated(void) +{ + return (gds_mitigation == GDS_MITIGATION_FULL || + gds_mitigation == GDS_MITIGATION_FULL_LOCKED); +} +EXPORT_SYMBOL_GPL(gds_ucode_mitigated); + void update_gds_msr(void) { u64 mcu_ctrl_after; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a6b9bea62fb8..ad09c8540189 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -314,6 +314,8 @@ u64 __read_mostly host_xcr0; static struct kmem_cache *x86_emulator_cache; +extern bool gds_ucode_mitigated(void); + /* * When called, it means the previous get/set msr reached an invalid msr. * Return true if we want to ignore/silent this failed msr access. @@ -1607,7 +1609,7 @@ static bool kvm_is_immutable_feature_msr(u32 msr) ARCH_CAP_SKIP_VMENTRY_L1DFLUSH | ARCH_CAP_SSB_NO | ARCH_CAP_MDS_NO | \ ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \ ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \ - ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO) + ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO) static u64 kvm_get_arch_capabilities(void) { @@ -1664,6 +1666,9 @@ static u64 kvm_get_arch_capabilities(void) */ } + if (!boot_cpu_has_bug(X86_BUG_GDS) || gds_ucode_mitigated()) + data |= ARCH_CAP_GDS_NO; + return data; } -- cgit v1.2.3 From 507397d19b5a296aa339f7a1bd16284f668a1906 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Jul 2023 10:02:18 +0300 Subject: iio: frequency: admv1013: propagate errors from regulator_get_voltage() The regulator_get_voltage() function returns negative error codes. This function saves it to an unsigned int and then does some range checking and, since the error code falls outside the correct range, it returns -EINVAL. Beyond the messiness, this is bad because the regulator_get_voltage() function can return -EPROBE_DEFER and it's important to propagate that back properly so it can be handled. Fixes: da35a7b526d9 ("iio: frequency: admv1013: add support for ADMV1013") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/ce75aac3-2aba-4435-8419-02e59fdd862b@moroto.mountain Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/admv1013.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index 9bf8337806fc..8c8e0bbfc99f 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -344,9 +344,12 @@ static int admv1013_update_quad_filters(struct admv1013_state *st) static int admv1013_update_mixer_vgate(struct admv1013_state *st) { - unsigned int vcm, mixer_vgate; + unsigned int mixer_vgate; + int vcm; vcm = regulator_get_voltage(st->reg); + if (vcm < 0) + return vcm; if (vcm < 1800000) mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100; -- cgit v1.2.3 From b2a69969908fcaf68596dfc04369af0fe2e1d2f7 Mon Sep 17 00:00:00 2001 From: Milan Zamazal Date: Wed, 19 Jul 2023 10:32:08 +0200 Subject: iio: core: Prevent invalid memory access when there is no parent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 813665564b3d ("iio: core: Convert to use firmware node handle instead of OF node") switched the kind of nodes to use for label retrieval in device registration. Probably an unwanted change in that commit was that if the device has no parent then NULL pointer is accessed. This is what happens in the stock IIO dummy driver when a new entry is created in configfs: # mkdir /sys/kernel/config/iio/devices/dummy/foo BUG: kernel NULL pointer dereference, address: ... ... Call Trace: __iio_device_register iio_dummy_probe Since there seems to be no reason to make a parent device of an IIO dummy device mandatory, let’s prevent the invalid memory access in __iio_device_register when the parent device is NULL. With this change, the IIO dummy driver works fine with configfs. Fixes: 813665564b3d ("iio: core: Convert to use firmware node handle instead of OF node") Reviewed-by: Andy Shevchenko Signed-off-by: Milan Zamazal Link: https://lore.kernel.org/r/20230719083208.88149-1-mzamazal@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index c117f50d0cf3..adcba832e6fa 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1888,7 +1888,7 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops; int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); - struct fwnode_handle *fwnode; + struct fwnode_handle *fwnode = NULL; int ret; if (!indio_dev->info) @@ -1899,7 +1899,8 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) /* If the calling driver did not initialize firmware node, do it here */ if (dev_fwnode(&indio_dev->dev)) fwnode = dev_fwnode(&indio_dev->dev); - else + /* The default dummy IIO device has no parent */ + else if (indio_dev->dev.parent) fwnode = dev_fwnode(indio_dev->dev.parent); device_set_node(&indio_dev->dev, fwnode); -- cgit v1.2.3 From 09738ccbc4148c62d6c8c4644ff4a099d57f49ad Mon Sep 17 00:00:00 2001 From: George Stark Date: Fri, 21 Jul 2023 13:23:08 +0300 Subject: iio: adc: meson: fix core clock enable/disable moment Enable core clock at probe stage and disable it at remove stage. Core clock is responsible for turning on/off the entire SoC module so it should be on before the first module register is touched and be off at very last moment. Fixes: 3adbf3427330 ("iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs") Signed-off-by: George Stark Link: https://lore.kernel.org/r/20230721102413.255726-2-gnstark@sberdevices.ru Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index af6bfcc19075..eb78a6f17fd0 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -916,12 +916,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) goto err_vref; } - ret = clk_prepare_enable(priv->core_clk); - if (ret) { - dev_err(dev, "failed to enable core clk\n"); - goto err_core_clk; - } - regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); @@ -948,8 +942,6 @@ err_adc_clk: regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, MESON_SAR_ADC_REG3_ADC_EN, 0); meson_sar_adc_set_bandgap(indio_dev, false); - clk_disable_unprepare(priv->core_clk); -err_core_clk: regulator_disable(priv->vref); err_vref: meson_sar_adc_unlock(indio_dev); @@ -977,8 +969,6 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev) meson_sar_adc_set_bandgap(indio_dev, false); - clk_disable_unprepare(priv->core_clk); - regulator_disable(priv->vref); if (!ret) @@ -1211,7 +1201,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) if (IS_ERR(priv->clkin)) return dev_err_probe(dev, PTR_ERR(priv->clkin), "failed to get clkin\n"); - priv->core_clk = devm_clk_get(dev, "core"); + priv->core_clk = devm_clk_get_enabled(dev, "core"); if (IS_ERR(priv->core_clk)) return dev_err_probe(dev, PTR_ERR(priv->core_clk), "failed to get core clk\n"); @@ -1294,15 +1284,26 @@ static int meson_sar_adc_remove(struct platform_device *pdev) static int meson_sar_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); meson_sar_adc_hw_disable(indio_dev); + clk_disable_unprepare(priv->core_clk); + return 0; } static int meson_sar_adc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + ret = clk_prepare_enable(priv->core_clk); + if (ret) { + dev_err(dev, "failed to enable core clk\n"); + return ret; + } return meson_sar_adc_hw_enable(indio_dev); } -- cgit v1.2.3 From 6811694eb2f6b7a4e97be2029edc7dd6a39460f8 Mon Sep 17 00:00:00 2001 From: Alejandro Tafalla Date: Fri, 14 Jul 2023 17:31:26 +0200 Subject: iio: imu: lsm6dsx: Fix mount matrix retrieval The function lsm6dsx_get_acpi_mount_matrix should return an error when ACPI support is not enabled to allow executing iio_read_mount_matrix in the probe function. Fixes: dc3d25f22b88 ("iio: imu: lsm6dsx: Add ACPI mount matrix retrieval") Signed-off-by: Alejandro Tafalla Acked-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/20230714153132.27265-1-atafalla@dnyon.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 6a18b363cf73..b6e6b1df8a61 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -2687,7 +2687,7 @@ unknown_format: static int lsm6dsx_get_acpi_mount_matrix(struct device *dev, struct iio_mount_matrix *orientation) { - return false; + return -EOPNOTSUPP; } #endif -- cgit v1.2.3 From 010c1e1c5741365dbbf44a5a5bb9f30192875c4c Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Thu, 20 Jul 2023 14:05:02 -0700 Subject: scsi: storvsc: Limit max_sectors for virtual Fibre Channel devices The Hyper-V host is queried to get the max transfer size that it supports, and this value is used to set max_sectors for the synthetic SCSI controller. However, this max transfer size may be too large for virtual Fibre Channel devices, which are limited to 512 Kbytes. If a larger transfer size is used with a vFC device, Hyper-V always returns an error, and storvsc logs a message like this where the SRB status and SCSI status are both zero: hv_storvsc : tag#197 cmd 0x8a status: scsi 0x0 srb 0x0 hv 0xc0000001 Add logic to limit the max transfer size to 512 Kbytes for vFC devices. Fixes: 1d3e0980782f ("scsi: storvsc: Correct reporting of Hyper-V I/O size limits") Cc: stable@vger.kernel.org Signed-off-by: Michael Kelley Link: https://lore.kernel.org/r/1689887102-32806-1-git-send-email-mikelley@microsoft.com Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 7f12d931fe7c..f2823218670a 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -366,6 +366,7 @@ static void storvsc_on_channel_callback(void *context); #define STORVSC_FC_MAX_LUNS_PER_TARGET 255 #define STORVSC_FC_MAX_TARGETS 128 #define STORVSC_FC_MAX_CHANNELS 8 +#define STORVSC_FC_MAX_XFER_SIZE ((u32)(512 * 1024)) #define STORVSC_IDE_MAX_LUNS_PER_TARGET 64 #define STORVSC_IDE_MAX_TARGETS 1 @@ -2006,6 +2007,9 @@ static int storvsc_probe(struct hv_device *device, * protecting it from any weird value. */ max_xfer_bytes = round_down(stor_device->max_transfer_bytes, HV_HYP_PAGE_SIZE); + if (is_fc) + max_xfer_bytes = min(max_xfer_bytes, STORVSC_FC_MAX_XFER_SIZE); + /* max_hw_sectors_kb */ host->max_sectors = max_xfer_bytes >> 9; /* -- cgit v1.2.3 From d5ace2a776442d80674eff9ed42e737f7dd95056 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Fri, 21 Jul 2023 21:51:16 -0700 Subject: x86/hyperv: Disable IBT when hypercall page lacks ENDBR instruction On hardware that supports Indirect Branch Tracking (IBT), Hyper-V VMs with ConfigVersion 9.3 or later support IBT in the guest. However, current versions of Hyper-V have a bug in that there's not an ENDBR64 instruction at the beginning of the hypercall page. Since hypercalls are made with an indirect call to the hypercall page, all hypercall attempts fail with an exception and Linux panics. A Hyper-V fix is in progress to add ENDBR64. But guard against the Linux panic by clearing X86_FEATURE_IBT if the hypercall page doesn't start with ENDBR. The VM will boot and run without IBT. If future Linux 32-bit kernels were to support IBT, additional hypercall page hackery would be needed to make IBT work for such kernels in a Hyper-V VM. Cc: stable@vger.kernel.org Signed-off-by: Michael Kelley Link: https://lore.kernel.org/r/1690001476-98594-1-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/hv_init.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 6c04b52f139b..953e280c07c3 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -471,6 +472,26 @@ void __init hyperv_init(void) wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); } + /* + * Some versions of Hyper-V that provide IBT in guest VMs have a bug + * in that there's no ENDBR64 instruction at the entry to the + * hypercall page. Because hypercalls are invoked via an indirect call + * to the hypercall page, all hypercall attempts fail when IBT is + * enabled, and Linux panics. For such buggy versions, disable IBT. + * + * Fixed versions of Hyper-V always provide ENDBR64 on the hypercall + * page, so if future Linux kernel versions enable IBT for 32-bit + * builds, additional hypercall page hackery will be required here + * to provide an ENDBR32. + */ +#ifdef CONFIG_X86_KERNEL_IBT + if (cpu_feature_enabled(X86_FEATURE_IBT) && + *(u32 *)hv_hypercall_pg != gen_endbr()) { + setup_clear_cpu_cap(X86_FEATURE_IBT); + pr_warn("Hyper-V: Disabling IBT because of Hyper-V bug\n"); + } +#endif + /* * hyperv_init() is called before LAPIC is initialized: see * apic_intr_mode_init() -> x86_platform.apic_post_init() and -- cgit v1.2.3 From 060f2b979c4e0e894c381c76a4dcad24376feddd Mon Sep 17 00:00:00 2001 From: ZhiHu Date: Sun, 23 Jul 2023 23:12:47 +0000 Subject: x86/hyperv: fix a warning in mshyperv.h The following checkpatch warning is removed: WARNING: Use #include instead of Signed-off-by: ZhiHu Reviewed-by: Michael Kelley Signed-off-by: Wei Liu --- arch/x86/include/asm/mshyperv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 49bb4f2bd300..cd17e706f9ca 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From ed0cf84e9cc42e6310961c87709621f1825c2bb8 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Wed, 5 Jul 2023 19:14:07 +0530 Subject: vmbus_testing: fix wrong python syntax for integer value comparison It is incorrect in python to compare integer values using the "is" keyword. The "is" keyword in python is used to compare references to two objects, not their values. Newer version of python3 (version 3.8) throws a warning when such incorrect comparison is made. For value comparison, "==" should be used. Fix this in the code and suppress the following warning: /usr/sbin/vmbus_testing:167: SyntaxWarning: "is" with a literal. Did you mean "=="? Signed-off-by: Ani Sinha Link: https://lore.kernel.org/r/20230705134408.6302-1-anisinha@redhat.com Signed-off-by: Wei Liu --- tools/hv/vmbus_testing | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hv/vmbus_testing b/tools/hv/vmbus_testing index e7212903dd1d..4467979d8f69 100755 --- a/tools/hv/vmbus_testing +++ b/tools/hv/vmbus_testing @@ -164,7 +164,7 @@ def recursive_file_lookup(path, file_map): def get_all_devices_test_status(file_map): for device in file_map: - if (get_test_state(locate_state(device, file_map)) is 1): + if (get_test_state(locate_state(device, file_map)) == 1): print("Testing = ON for: {}" .format(device.split("/")[5])) else: @@ -203,7 +203,7 @@ def write_test_files(path, value): def set_test_state(state_path, state_value, quiet): write_test_files(state_path, state_value) - if (get_test_state(state_path) is 1): + if (get_test_state(state_path) == 1): if (not quiet): print("Testing = ON for device: {}" .format(state_path.split("/")[5])) -- cgit v1.2.3 From 92d39d018347ead1078dcba3cb1d8aeb9de79e04 Mon Sep 17 00:00:00 2001 From: Durai Manickam KR Date: Tue, 18 Jul 2023 12:27:34 +0530 Subject: dt-bindings: serial: atmel,at91-usart: update compatible for sam9x60 There is only one debug unit in the sam9x60 SOC and it has the chipid register. So, the dbgu compatible strings are valid only for debug usart. Defining these dbgu compatible strings are not valid for flexcom usart. So adding the items which is valid only for flexcom usart and removing the microchip,sam9x60-usart compatible string from the enum list as no usart node defines only this specific compatible string. Signed-off-by: Durai Manickam KR Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230718065735.10187-2-durai.manickamkr@microchip.com Signed-off-by: Arnd Bergmann --- Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml index 30b2131b5860..65cb2e5c5eee 100644 --- a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml +++ b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml @@ -16,13 +16,15 @@ properties: - enum: - atmel,at91rm9200-usart - atmel,at91sam9260-usart - - microchip,sam9x60-usart - items: - const: atmel,at91rm9200-dbgu - const: atmel,at91rm9200-usart - items: - const: atmel,at91sam9260-dbgu - const: atmel,at91sam9260-usart + - items: + - const: microchip,sam9x60-usart + - const: atmel,at91sam9260-usart - items: - const: microchip,sam9x60-dbgu - const: microchip,sam9x60-usart -- cgit v1.2.3 From 421033deb91521aa6a9255e495cb106741a52275 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Mon, 5 Jun 2023 10:34:07 +0300 Subject: wifi: mt76: mt7615: do not advertise 5 GHz on first phy of MT7615D (DBDC) On DBDC devices the first (internal) phy is only capable of using 2.4 GHz band, and the 5 GHz band is exposed via a separate phy object, so avoid the false advertising. Reported-by: Rani Hod Closes: https://github.com/openwrt/openwrt/pull/12361 Fixes: 7660a1bd0c22 ("mt76: mt7615: register ext_phy if DBDC is detected") Cc: stable@vger.kernel.org Signed-off-by: Paul Fertser Reviewed-by: Simon Horman Acked-by: Felix Fietkau Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230605073408.8699-1-fercerpav@gmail.com --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 68e88224b8b1..ccedea7e8a50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -128,12 +128,12 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev) case MT_EE_5GHZ: dev->mphy.cap.has_5ghz = true; break; - case MT_EE_2GHZ: - dev->mphy.cap.has_2ghz = true; - break; case MT_EE_DBDC: dev->dbdc_support = true; fallthrough; + case MT_EE_2GHZ: + dev->mphy.cap.has_2ghz = true; + break; default: dev->mphy.cap.has_2ghz = true; dev->mphy.cap.has_5ghz = true; -- cgit v1.2.3 From a2777be03236c00466326acba8d39ac4f9c3e971 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 21 Jul 2023 16:06:04 -0700 Subject: MAINTAINERS: Update mwifiex maintainer list We haven't heard anything from these folks in years. I've been reviewing many submissions and plan to keep doing so. Cc: Amitkumar Karwar Cc: Ganapathi Bhat Cc: Sharvari Harisangam Cc: Xinming Hu Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230721160603.1.Idf0e8025f59c62d73c08960638249b58cf215acc@changeid --- MAINTAINERS | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index dfbb271f1667..42e78a696be6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12579,12 +12579,9 @@ F: Documentation/devicetree/bindings/net/marvell,pp2.yaml F: drivers/net/ethernet/marvell/mvpp2/ MARVELL MWIFIEX WIRELESS DRIVER -M: Amitkumar Karwar -M: Ganapathi Bhat -M: Sharvari Harisangam -M: Xinming Hu +M: Brian Norris L: linux-wireless@vger.kernel.org -S: Maintained +S: Odd Fixes F: drivers/net/wireless/marvell/mwifiex/ MARVELL MWL8K WIRELESS DRIVER -- cgit v1.2.3 From aead78125a987f48944bff2001f61df72b95afc4 Mon Sep 17 00:00:00 2001 From: Anh Tuan Phan Date: Sun, 16 Jul 2023 22:44:56 +0700 Subject: tools/counter: Makefile: Replace rmdir by rm to avoid make,clean failure Use rm -df instead of rmdir -p since rmdir requires the directory exist so it causes "make -C tools clean" failed if someone only builds other tools but not counter. Fixes: 228354ed692f ("tools/counter: Makefile: Remove lingering 'include' directories on make clean") Signed-off-by: Anh Tuan Phan Link: https://lore.kernel.org/r/d4080db5-1825-2848-079a-8bb674d8ee44@gmail.com/ Signed-off-by: William Breathitt Gray --- tools/counter/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/counter/Makefile b/tools/counter/Makefile index a0f4cab71fe5..b2c2946f44c9 100644 --- a/tools/counter/Makefile +++ b/tools/counter/Makefile @@ -40,7 +40,8 @@ $(OUTPUT)counter_example: $(COUNTER_EXAMPLE) clean: rm -f $(ALL_PROGRAMS) rm -rf $(OUTPUT)include/linux/counter.h - rmdir -p $(OUTPUT)include/linux + rm -df $(OUTPUT)include/linux + rm -df $(OUTPUT)include find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete install: $(ALL_PROGRAMS) -- cgit v1.2.3 From 9754353d0ab123d71bf572a483ecc8b330ef36a3 Mon Sep 17 00:00:00 2001 From: Haixin Yu Date: Mon, 24 Jul 2023 13:06:54 +0800 Subject: perf pmu arm64: Fix reading the PMU cpu slots in sysfs Commit f8ad6018ce3c065a ("perf pmu: Remove duplication around EVENT_SOURCE_DEVICE_PATH") uses sysfs__read_ull() to read a full sysfs path, which will never succeeds as it already comes with the sysfs mount point in it, which sysfs__read_ull() will add again. Fix it by reading the file using filename__read_ull(), that will not add the sysfs mount point. Fixes: f8ad6018ce3c065a ("perf pmu: Remove duplication around EVENT_SOURCE_DEVICE_PATH") Signed-off-by: Haixin Yu Tested-by: Jing Zhang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/ZL4G7rWXkfv-Ectq@B-Q60VQ05P-2326.local Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/pmu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c index 561de0cb6b95..512a8f13c4de 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -54,10 +54,11 @@ double perf_pmu__cpu_slots_per_cycle(void) perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, "caps/slots"); /* - * The value of slots is not greater than 32 bits, but sysfs__read_int - * can't read value with 0x prefix, so use sysfs__read_ull instead. + * The value of slots is not greater than 32 bits, but + * filename__read_int can't read value with 0x prefix, + * so use filename__read_ull instead. */ - sysfs__read_ull(path, &slots); + filename__read_ull(path, &slots); } return slots ? (double)slots : NAN; -- cgit v1.2.3 From 341e0e9f59e26676c88d0aa9a5a9b2d3c44bf21c Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Mon, 24 Jul 2023 22:28:15 +0530 Subject: perf callchain powerpc: Fix addr location init during arch_skip_callchain_idx function 'perf record; with callchain recording fails as below in powerpc: ./perf record -a -gR sleep 10 ./perf report perf: Segmentation fault gdb trace points to thread__find_map 0 0x00000000101df314 in atomic_cmpxchg (newval=1818846826, oldval=1818846827, v=0x1001a8f3) at /home/athira/linux/tools/include/asm-generic/atomic-gcc.h:70 1 refcount_sub_and_test (i=1, r=0x1001a8f3) at /home/athira/linux/tools/include/linux/refcount.h:135 2 refcount_dec_and_test (r=0x1001a8f3) at /home/athira/linux/tools/include/linux/refcount.h:148 3 map__put (map=0x1001a8b3) at util/map.c:311 4 0x000000001016842c in __map__zput (map=0x7fffffffa368) at util/map.h:190 5 thread__find_map (thread=0x105b92f0, cpumode=, addr=13835058055283572736, al=al@entry=0x7fffffffa358) at util/event.c:582 6 0x000000001016882c in thread__find_symbol (thread=, cpumode=, addr=, al=0x7fffffffa358) at util/event.c:656 7 0x00000000102e12b4 in arch_skip_callchain_idx (thread=, chain=) at arch/powerpc/util/skip-callchain-idx.c:255 8 0x00000000101d3bf4 in thread__resolve_callchain_sample (thread=0x105b92f0, cursor=0x1053d160, evsel=, sample=0x7fffffffa908, parent=0x7fffffffa778, root_al=0x7fffffffa710, max_stack=) at util/machine.c:2940 9 0x00000000101cd210 in sample__resolve_callchain (sample=, cursor=, parent=, evsel=, al=, max_stack=) at util/callchain.c:1112 10 0x000000001022a9d8 in hist_entry_iter__add (iter=0x7fffffffa750, al=0x7fffffffa710, max_stack_depth=, arg=0x7fffffffbbd0) at util/hist.c:1232 11 0x0000000010056d98 in process_sample_event (tool=0x7fffffffbbd0, event=0x7ffff6223c38, sample=0x7fffffffa908, evsel=, machine=0x10524ef8) at builtin-report.c:332 Here arch_skip_callchain_idx calls thread__find_symbol and which invokes thread__find_map with uninitialised "addr_location". Snippet: thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); Recent change with commit 0dd5041c9a0eaf8c ("perf addr_location: Add init/exit/copy functions") , introduced "maps__zput" in the function thread__find_map. This could result in segfault while accessing uninitialised map from "struct addr_location". Fix this by adding addr_location__init and addr_location__exit in arch_skip_callchain_idx. Fixes: 0dd5041c9a0eaf8c ("perf addr_location: Add init/exit/copy functions") Reported-by: Aneesh Kumar K.V Signed-off-by: Athira Rajeev Cc: Disha Goel Cc: Ian Rogers Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230724165815.17810-1-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index b7223feec770..5f3edb3004d8 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -250,6 +250,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) if (!chain || chain->nr < 3) return skip_slot; + addr_location__init(&al); ip = chain->ips[1]; thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); @@ -259,6 +260,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) if (!dso) { pr_debug("%" PRIx64 " dso is NULL\n", ip); + addr_location__exit(&al); return skip_slot; } @@ -279,5 +281,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) */ skip_slot = 3; } + + addr_location__exit(&al); return skip_slot; } -- cgit v1.2.3 From 4c188fa183ebb45238ef16504c4c7606955cf9d4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 24 Jul 2023 10:19:25 +0100 Subject: arm64: dts: renesas: rzg2l: Update overfow/underflow IRQ names for MTU3 channels As per R01UH0914EJ0130 Rev.1.30 HW manual the MTU3 overflow/underflow interrupt names start with 'tci' instead of 'tgi'. Replace the below overflow/underflow interrupt names: - tgiv0->tciv0 - tgiv1->tciv1 - tgiu1->tciu1 - tgiv2->tciv2 - tgiu2->tciu2 - tgiv3->tciv3 - tgiv4->tciv4 - tgiv6->tciv6 - tgiv7->tciv7 - tgiv8->tciv8 - tgiu8->tciu8 Fixes: 26336d66d021 ("arm64: dts: renesas: r9a07g044: Add MTU3a node") Fixes: dd123dd01def ("arm64: dts: renesas: r9a07g054: Add MTU3a node") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230724091927.123847-5-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 16 ++++++++-------- arch/arm64/boot/dts/renesas/r9a07g054.dtsi | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi index 232910e07444..66f68fc2b241 100644 --- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi @@ -223,20 +223,20 @@ , ; interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", - "tgiv0", "tgie0", "tgif0", - "tgia1", "tgib1", "tgiv1", "tgiu1", - "tgia2", "tgib2", "tgiv2", "tgiu2", + "tciv0", "tgie0", "tgif0", + "tgia1", "tgib1", "tciv1", "tciu1", + "tgia2", "tgib2", "tciv2", "tciu2", "tgia3", "tgib3", "tgic3", "tgid3", - "tgiv3", + "tciv3", "tgia4", "tgib4", "tgic4", "tgid4", - "tgiv4", + "tciv4", "tgiu5", "tgiv5", "tgiw5", "tgia6", "tgib6", "tgic6", "tgid6", - "tgiv6", + "tciv6", "tgia7", "tgib7", "tgic7", "tgid7", - "tgiv7", + "tciv7", "tgia8", "tgib8", "tgic8", "tgid8", - "tgiv8", "tgiu8"; + "tciv8", "tciu8"; clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>; power-domains = <&cpg>; resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>; diff --git a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi index 2eba3a8a100d..1f1d481dc783 100644 --- a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi @@ -223,20 +223,20 @@ , ; interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", - "tgiv0", "tgie0", "tgif0", - "tgia1", "tgib1", "tgiv1", "tgiu1", - "tgia2", "tgib2", "tgiv2", "tgiu2", + "tciv0", "tgie0", "tgif0", + "tgia1", "tgib1", "tciv1", "tciu1", + "tgia2", "tgib2", "tciv2", "tciu2", "tgia3", "tgib3", "tgic3", "tgid3", - "tgiv3", + "tciv3", "tgia4", "tgib4", "tgic4", "tgid4", - "tgiv4", + "tciv4", "tgiu5", "tgiv5", "tgiw5", "tgia6", "tgib6", "tgic6", "tgid6", - "tgiv6", + "tciv6", "tgia7", "tgib7", "tgic7", "tgid7", - "tgiv7", + "tciv7", "tgia8", "tgib8", "tgic8", "tgid8", - "tgiv8", "tgiu8"; + "tciv8", "tciu8"; clocks = <&cpg CPG_MOD R9A07G054_MTU_X_MCK_MTU3>; power-domains = <&cpg>; resets = <&cpg R9A07G054_MTU_X_PRESET_MTU3>; -- cgit v1.2.3 From 4005d1ba0a7e5cf32f669bf0014dca0dd12c2a44 Mon Sep 17 00:00:00 2001 From: Peter Suti Date: Thu, 13 Jul 2023 11:52:58 +0200 Subject: ASoC: soc-dai: don't call PCM audio ops if the stream is not supported PCM audio ops may be called when the stream is not supported. We should not call the ops in that case to avoid unexpected behavior. hw_params is handled already in soc-pcm.c [0] https://lore.kernel.org/alsa-devel/ae06b00a-f3f7-f9d1-0b58-4d71f3394416@linux.intel.com/T/#t Signed-off-by: Peter Suti Link: https://lore.kernel.org/r/20230713095258.3393827-1-peter.suti@streamunlimited.com Signed-off-by: Mark Brown --- sound/soc/soc-dai.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 02dd64dea179..73a97ac6ccb8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -424,6 +424,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->startup) ret = dai->driver->ops->startup(substream, dai); @@ -439,6 +442,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int rollback) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return; + if (rollback && !soc_dai_mark_match(dai, substream, startup)) return; @@ -603,6 +609,8 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream) int i, ret; for_each_rtd_dais(rtd, i, dai) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + continue; if (dai->driver->ops && dai->driver->ops->prepare) { ret = dai->driver->ops->prepare(substream, dai); @@ -619,6 +627,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->trigger) ret = dai->driver->ops->trigger(substream, cmd, dai); -- cgit v1.2.3 From 4ddad00c609bdcd6635537d3acb9bd57a5fc79e6 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:19 +0800 Subject: ASoC: codecs: ES8326: Change Hp_detect register names The old register naming method is confusing. The reg 0x57 decides the default headset hardware connection type, and the reg 0xfb is the headset detection status register, which changes during headset insertion. Change the name to ES8326_HPDET_TYPE and ES8326_HPDET_STA. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-1-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 10 +++++----- sound/soc/codecs/es8326.h | 13 ++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index a7fbb758eeee..b62fff48f70c 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -159,7 +159,7 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { }; static const struct regmap_range es8326_volatile_ranges[] = { - regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT), + regmap_reg_range(ES8326_HPDET_STA, ES8326_HPDET_STA), }; static const struct regmap_access_table es8326_volatile_table = { @@ -519,7 +519,7 @@ static void es8326_jack_button_handler(struct work_struct *work) return; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); switch (iface) { case 0x93: /* pause button detected */ @@ -578,7 +578,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) unsigned int iface; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); if ((iface & ES8326_HPINSERT_FLAG) == 0) { /* Jack unplugged or spurious IRQ */ @@ -651,7 +651,7 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); - regmap_write(es8326->regmap, ES8326_HP_DET, + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); @@ -743,7 +743,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, mutex_lock(&es8326->lock); if (es8326->jd_inverted) - snd_soc_component_update_bits(component, ES8326_HP_DET, + snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); es8326->jack = jack; diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index 3f8f7da58062..cd04d11a88d9 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -73,15 +73,19 @@ #define ES8326_DRC_RECOVERY 0x53 #define ES8326_DRC_WINSIZE 0x54 #define ES8326_HPJACK_TIMER 0x56 -#define ES8326_HP_DET 0x57 +#define ES8326_HPDET_TYPE 0x57 #define ES8326_INT_SOURCE 0x58 #define ES8326_INTOUT_IO 0x59 #define ES8326_SDINOUT1_IO 0x5A #define ES8326_SDINOUT23_IO 0x5B #define ES8326_JACK_PULSE 0x5C +#define ES8326_HP_MISC 0xF7 +#define ES8326_CTIA_OMTP_STA 0xF8 #define ES8326_PULLUP_CTL 0xF9 -#define ES8326_HP_DETECT 0xFB +#define ES8326_CSM_I2C_STA 0xFA +#define ES8326_HPDET_STA 0xFB +#define ES8326_CSM_MUTE_STA 0xFC #define ES8326_CHIP_ID1 0xFD #define ES8326_CHIP_ID2 0xFE #define ES8326_CHIP_VERSION 0xFF @@ -146,7 +150,7 @@ #define ES8326_ADC3_SHIFT 0 #define ES8326_ADC4_SHIFT 3 -/* ES8326_HP_DET */ +/* ES8326_HPDET_TYPE */ #define ES8326_HP_DET_SRC_PIN27 (1 << 5) #define ES8326_HP_DET_SRC_PIN9 (1 << 4) #define ES8326_HP_DET_JACK_POL (1 << 3) @@ -174,7 +178,7 @@ #define ES8326_SDINOUT2_SHIFT 4 #define ES8326_SDINOUT3_SHIFT 0 -/* ES8326_HP_DETECT */ +/* ES8326_HPDET_STA */ #define ES8326_HPINSERT_FLAG (1 << 1) #define ES8326_HPBUTTON_FLAG (1 << 0) @@ -182,4 +186,3 @@ #define ES8326_VERSION_B (1 << 0) #endif - -- cgit v1.2.3 From f1230a27c14b4d05e1d6af02be55c617b53728a4 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:20 +0800 Subject: ASoC: codecs: ES8326: Change Volatile Reg function The new calibration and headphone detection function require reading new volatile registers. Add them in the volatile register function. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-2-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index b62fff48f70c..9f4408dcf3af 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -158,20 +158,25 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"HPOR", NULL, "RHPMIX"}, }; -static const struct regmap_range es8326_volatile_ranges[] = { - regmap_reg_range(ES8326_HPDET_STA, ES8326_HPDET_STA), -}; - -static const struct regmap_access_table es8326_volatile_table = { - .yes_ranges = es8326_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), -}; +static bool es8326_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ES8326_HPL_OFFSET_INI: + case ES8326_HPR_OFFSET_INI: + case ES8326_HPDET_STA: + case ES8326_CTIA_OMTP_STA: + case ES8326_CSM_MUTE_STA: + return true; + default: + return false; + } +} static const struct regmap_config es8326_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, - .volatile_table = &es8326_volatile_table, + .volatile_reg = es8326_volatile_register, .cache_type = REGCACHE_RBTREE, }; -- cgit v1.2.3 From ac20a73d765c0374f5e7b5d0f2f43c4598d69c66 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:21 +0800 Subject: ASoC: codecs: ES8326: Fix power-up sequence Old power-up sequence causes large pop noise during start-up. Using a new sequence instead. Also, the registers are now reset to default value in suspend function. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-3-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 95 +++++++++++++++++++++++++++++++++-------------- sound/soc/codecs/es8326.h | 10 ++++- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 9f4408dcf3af..ffb61a3cbfe4 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -638,40 +638,77 @@ out: static int es8326_resume(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - unsigned int reg; regcache_cache_only(es8326->regmap, false); regcache_sync(es8326->regmap); + /* reset internal clock state */ + regmap_write(es8326->regmap, ES8326_RESET, 0x1f); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); + usleep_range(10000, 15000); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + /* set headphone default type and detect pin */ + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + + /* set internal oscillator as clock source of headpone cp */ + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84); regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); - /* Two channel ADC */ - regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02); + /* clock manager reset release */ + regmap_write(es8326->regmap, ES8326_RESET, 0x17); + /* set headphone detection as half scan mode */ + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08); + regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00); + + /* enable headphone driver */ + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); - regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88); - regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00); + + /* turn off headphone out */ + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00); + /* set ADC and DAC in low power mode */ + regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); + + /* force micbias on */ + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f); regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22); - regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); - regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); - regmap_write(es8326->regmap, ES8326_HPDET_TYPE, - ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); + /* select vdda as micbias source */ + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23); + /* set dac dsmclip = 1 */ + regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08); + regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15); + + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, + es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); - snd_soc_component_update_bits(component, ES8326_PGAGAIN, - ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); - - regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); - if ((reg & ES8326_VERSION_B) == 1) { - regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD); - regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); - regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F); - /* enable button detect */ - regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0); - } + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK, + ES8326_MIC1_SEL); + + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, + ES8326_MUTE); + + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 | + ((es8326->version == ES8326_VERSION_B) ? + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); es8326_irq(es8326->irq, es8326); return 0; @@ -688,6 +725,10 @@ static int es8326_suspend(struct snd_soc_component *component) regcache_cache_only(es8326->regmap, true); regcache_mark_dirty(es8326->regmap); + /* reset register value to default */ + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01); + usleep_range(1000, 3000); + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00); return 0; } @@ -717,7 +758,7 @@ static int es8326_probe(struct snd_soc_component *component) ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); if (ret != 0) { dev_dbg(component->dev, "jack-pol return %d", ret); - es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; + es8326->jack_pol = ES8326_HP_TYPE_AUTO; } dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index cd04d11a88d9..90a08351d6ac 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -160,6 +160,13 @@ #define ES8326_HP_TYPE_AUTO (1 << 0) #define ES8326_HP_TYPE_AUTO_INV (0 << 0) +/* ES8326_INT_SOURCE */ +#define ES8326_INT_SRC_DAC_MOZ (1 << 0) +#define ES8326_INT_SRC_ADC_MOZ (1 << 1) +#define ES8326_INT_SRC_BUTTON (1 << 2) +#define ES8326_INT_SRC_PIN9 (1 << 3) +#define ES8326_INT_SRC_PIN27 (1 << 4) + /* ES8326_SDINOUT1_IO */ #define ES8326_IO_INPUT (0 << 0) #define ES8326_IO_SDIN_SLOT0 (1 << 0) @@ -183,6 +190,7 @@ #define ES8326_HPBUTTON_FLAG (1 << 0) /* ES8326_CHIP_VERSION 0xFF */ -#define ES8326_VERSION_B (1 << 0) +#define ES8326_VERSION (1 << 0) +#define ES8326_VERSION_B (3 << 0) #endif -- cgit v1.2.3 From 0663286e58e6f611f3578b5e63e1faa576d139fd Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:22 +0800 Subject: ASOC: codecs: ES8326: Add calibration support for version_b Version_b requires a new way of calibrating headset offset. A new calibration function is added. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-4-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 83 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index ffb61a3cbfe4..8ffabc8cd33e 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -388,6 +388,7 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) { struct snd_soc_component *component = dai->component; struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int offset_l, offset_r; if (mute) { regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); @@ -398,10 +399,16 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) if (!es8326->calibrated) { regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL); msleep(30); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); es8326->calibrated = true; } regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0); - regmap_write(es8326->regmap, ES8326_HP_VOL, 0x00); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, ~(ES8326_MUTE)); @@ -420,15 +427,17 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, ret = clk_prepare_enable(es8326->mclk); if (ret) return ret; - regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45); + + regmap_write(es8326->regmap, ES8326_RESET, 0x9f); + msleep(20); + regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); - regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); break; case SND_SOC_BIAS_PREPARE: @@ -437,15 +446,10 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, break; case SND_SOC_BIAS_OFF: clk_disable_unprepare(es8326->mclk); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11); - regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF); - regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_RESET, - ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); break; } @@ -635,6 +639,54 @@ out: return IRQ_HANDLED; } +static int es8326_calibrate(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int reg; + unsigned int offset_l, offset_r; + + regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); + es8326->version = reg; + + if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) { + dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n"); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0); + regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01); + regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30); + regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed); + regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1); + regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_RESET, 0xc0); + usleep_range(15000, 20000); + + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, ®); + if ((reg & 0xf0) != 0x40) + msleep(50); + + regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); + + es8326->calibrated = true; + } + + return 0; +} + static int es8326_resume(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); @@ -673,7 +725,8 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4); regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81); regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00); - + /* calibrate for B version */ + es8326_calibrate(component); /* turn off headphone out */ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00); /* set ADC and DAC in low power mode */ -- cgit v1.2.3 From 04f96c9340463aae20d2511a3d6cb0b005b07d24 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:23 +0800 Subject: ASoC: codecs: ES8326: Update jact detection function The old jack detection function only supports fixed OMTP/CTIA hardware connection. The new one supports auto OMTP/CTIA headset detection Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-5-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 109 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 8ffabc8cd33e..6c263086c44d 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -41,6 +41,8 @@ struct es8326_priv { bool calibrated; int version; + int hp; + int jack_remove_retry; }; static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -535,6 +537,7 @@ static void es8326_jack_button_handler(struct work_struct *work) cur_button = SND_JACK_BTN_0; break; case 0x6f: + case 0x4b: /* button volume up */ cur_button = SND_JACK_BTN_1; break; @@ -543,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work) cur_button = SND_JACK_BTN_2; break; case 0x1e: + case 0xe2: /* button released or not pressed */ cur_button = 0; break; @@ -552,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work) if ((prev_button == cur_button) && (cur_button != 0)) { press_count++; - if (press_count > 10) { - /* report a press every 500ms */ + if (press_count > 3) { + /* report a press every 120ms */ snd_soc_jack_report(es8326->jack, cur_button, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); press_count = 0; } button_to_report = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else if (prev_button != cur_button) { /* mismatch, detect again */ prev_button = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else { /* released or no pressed */ if (button_to_report != 0) { @@ -589,32 +593,96 @@ static void es8326_jack_detect_handler(struct work_struct *work) mutex_lock(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); + + if (es8326->jack_remove_retry == 1) { + if (iface & ES8326_HPINSERT_FLAG) + es8326->jack_remove_retry = 2; + else + es8326->jack_remove_retry = 0; + + dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n", + es8326->jack_remove_retry); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + ~es8326->jack_pol : es8326->jack_pol)); + goto exit; + } + if ((iface & ES8326_HPINSERT_FLAG) == 0) { /* Jack unplugged or spurious IRQ */ - dev_dbg(comp->dev, "No headset detected"); + dev_dbg(comp->dev, "No headset detected\n"); + es8326_disable_micbias(es8326->component); if (es8326->jack->status & SND_JACK_HEADPHONE) { + dev_dbg(comp->dev, "Report hp remove event\n"); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); - snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src); - es8326_disable_micbias(comp); + /* mute adc when mic path switch */ + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); + es8326->hp = 0; + } + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + if (es8326->jack_remove_retry == 0) { + es8326->jack_remove_retry = 1; + dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", + es8326->jack_remove_retry); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + es8326->jack_pol : ~es8326->jack_pol)); + + } else { + es8326->jack_remove_retry = 0; } } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) { + es8326->jack_remove_retry = 0; + if (es8326->hp == 0) { + dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n"); + /* + * set auto-check mode, then restart jack_detect_work after 100ms. + * Don't report jack status. + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + usleep_range(50000, 70000); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(100)); + es8326->hp = 1; + goto exit; + } if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ + dev_dbg(comp->dev, "button pressed\n"); queue_delayed_work(system_wq, &es8326->button_press_work, 10); + goto exit; + } + if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { + dev_dbg(comp->dev, "Headphone detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADPHONE, SND_JACK_HEADSET); } else { - if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) { - dev_dbg(comp->dev, "Headset detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADSET, SND_JACK_HEADSET); - snd_soc_component_write(comp, - ES8326_ADC1_SRC, es8326->mic1_src); - } else { - dev_dbg(comp->dev, "Headphone detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADPHONE, SND_JACK_HEADSET); - } + dev_dbg(comp->dev, "Headset detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADSET, SND_JACK_HEADSET); + + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x08); + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, + 0x80, 0x80); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x00); + usleep_range(10000, 15000); } } +exit: mutex_unlock(&es8326->lock); } @@ -633,7 +701,7 @@ static irqreturn_t es8326_irq(int irq, void *dev_id) msecs_to_jiffies(10)); else queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(300)); + msecs_to_jiffies(600)); out: return IRQ_HANDLED; @@ -763,7 +831,8 @@ static int es8326_resume(struct snd_soc_component *component) (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); - es8326_irq(es8326->irq, es8326); + es8326->jack_remove_retry = 0; + es8326->hp = 0; return 0; } -- cgit v1.2.3 From 2b7aecd58528551e6e3da58091ff7ceb4718e6be Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Tue, 18 Jul 2023 16:42:38 +0800 Subject: ASoC: rt1017: Add RT1017 SDCA amplifier driver This is the initial amplifier driver for rt1017 SDCA version. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20230718084238.3692-1-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1017-sdca-sdw.c | 824 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1017-sdca-sdw.h | 188 +++++++++ 4 files changed, 1020 insertions(+) create mode 100644 sound/soc/codecs/rt1017-sdca-sdw.c create mode 100644 sound/soc/codecs/rt1017-sdca-sdw.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 88c3dbe47d71..8aba442d1978 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -184,6 +184,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1015 imply SND_SOC_RT1015P imply SND_SOC_RT1016 + imply SND_SOC_RT1017_SDCA_SDW imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 @@ -1428,6 +1429,11 @@ config SND_SOC_RT1016 tristate depends on I2C +config SND_SOC_RT1017_SDCA_SDW + tristate "Realtek RT1017 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + config SND_SOC_RT1019 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 32dcc6de58bd..be367839cfa4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -205,6 +205,7 @@ snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o snd-soc-rt1016-objs := rt1016.o +snd-soc-rt1017-sdca-objs := rt1017-sdca-sdw.o snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o @@ -583,6 +584,7 @@ obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o +obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW) += snd-soc-rt1017-sdca.o obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c new file mode 100644 index 000000000000..7295f44c77eb --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -0,0 +1,824 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2023 Realtek Semiconductor Corp. +// +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt1017-sdca-sdw.h" + +static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0x3206: + case 0xc000: + case 0xc001: + case 0xc022: + case 0xc030: + case 0xc104: + case 0xc10b: + case 0xc10c: + case 0xc110: + case 0xc112: + case 0xc300: + case 0xc301: + case 0xc318: + case 0xc325 ... 0xc328: + case 0xc331: + case 0xc340: + case 0xc350 ... 0xc351: + case 0xc500: + case 0xc502: + case 0xc504: + case 0xc507: + case 0xc509: + case 0xc510: + case 0xc512: + case 0xc518: + case 0xc51b: + case 0xc51d: + case 0xc520: + case 0xc540 ... 0xc542: + case 0xc550 ... 0xc552: + case 0xc600: + case 0xc602: + case 0xc612: + case 0xc622: + case 0xc632: + case 0xc642: + case 0xc651: + case 0xca00: + case 0xca09 ... 0xca0c: + case 0xca0e ... 0xca0f: + case 0xca10 ... 0xca11: + case 0xca16 ... 0xca17: + case 0xcb00: + case 0xcc00: + case 0xcc02: + case 0xd017: + case 0xd01a ... 0xd01c: + case 0xd101: + case 0xd20c: + case 0xd300: + case 0xd370: + case 0xd500: + case 0xd545 ... 0xd548: + case 0xd5a5 ... 0xd5a8: + case 0xd5aa ... 0xd5ad: + case 0xda04 ... 0xda07: + case 0xda09 ... 0xda0a: + case 0xda0c ... 0xda0f: + case 0xda11 ... 0xda14: + case 0xda16 ... 0xda19: + case 0xdab6 ... 0xdabb: + case 0xdb09 ... 0xdb0a: + case 0xdb14: + + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + return true; + default: + return false; + } +} + +static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0xc000: + case 0xc022: + case 0xc351: + case 0xc518: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + return true; + default: + return false; + } +} + +static const struct reg_sequence rt1017_blind_write[] = { + { 0xc001, 0x43 }, + { 0x2f55, 0x02 }, + { 0x3206, 0x80 }, + { 0x005f, 0x7f }, + { 0xd101, 0xa0 }, + { 0xc112, 0xc0 }, + { 0xc104, 0xaa }, + { 0xc110, 0x59 }, + { 0xc112, 0xc0 }, + { 0xc340, 0x80 }, + { 0xd017, 0x2c }, + { 0xd01a, 0xc8 }, + { 0xd01b, 0xcf }, + { 0xd01c, 0x0c }, + { 0xd20c, 0x14 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0x7f }, + { 0xdb14, 0x03 }, + { 0xcb00, 0x31 }, + { 0xc318, 0x44 }, + { 0xc325, 0xce }, + { 0xc326, 0x13 }, + { 0xc327, 0x5f }, + { 0xc328, 0xf3 }, + { 0xc350, 0xe1 }, + { 0xc351, 0x88 }, + { 0xc030, 0x14 }, + { 0xc331, 0xf2 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc651, 0xc0 }, + { 0xc550, 0xd0 }, + { 0xc612, 0x00 }, + { 0xc622, 0x00 }, + { 0xc632, 0x00 }, + { 0xc642, 0x00 }, + { 0xc602, 0xf0 }, + { 0xc600, 0xd0 }, + { 0xcc02, 0x78 }, + { 0xcc00, 0x90 }, + { 0xc300, 0x3f }, + { 0xc301, 0x1d }, + { 0xc10b, 0x2e }, + { 0xc10c, 0x36 }, + + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x6a }, + { 0xd5a7, 0xaa }, + { 0xd5a8, 0xaa }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x16 }, + { 0xd5ac, 0xdb }, + { 0xd5ad, 0x6d }, + { 0xd545, 0x09 }, + { 0xd546, 0x30 }, + { 0xd547, 0xf0 }, + { 0xd548, 0xf0 }, + { 0xd500, 0x20 }, + { 0xc504, 0x3f }, + { 0xc540, 0x00 }, + { 0xc541, 0x0a }, + { 0xc542, 0x1a }, + { 0xc512, 0x00 }, + { 0xc520, 0x40 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc500, 0x40 }, + { 0xc502, 0xde }, + { 0xc507, 0x05 }, + { 0xc509, 0x05 }, + { 0xc510, 0x40 }, + { 0xc518, 0xc0 }, + { 0xc500, 0xc0 }, + + { 0xda0c, 0x00 }, + { 0xda0d, 0x0b }, + { 0xda0e, 0x55 }, + { 0xda0f, 0x55 }, + { 0xda04, 0x00 }, + { 0xda05, 0x51 }, + { 0xda06, 0xeb }, + { 0xda07, 0x85 }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda11, 0x26 }, + { 0xda12, 0x66 }, + { 0xda13, 0x66 }, + { 0xda14, 0x66 }, + { 0xda16, 0x79 }, + { 0xda17, 0x99 }, + { 0xda18, 0x99 }, + { 0xda19, 0x99 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x07 }, + { 0xca0b, 0x89 }, + { 0xca0c, 0x61 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x03 }, + { 0xca10, 0xc4 }, + { 0xca11, 0xb0 }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x00 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x00 }, + { 0xd017, 0x0e }, + { 0xca00, 0xcd }, + { 0xc022, 0x84 }, +}; + +#define RT1017_MAX_REG_NUM 0x4108ffff + +static const struct regmap_config rt1017_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1017_sdca_readable_register, + .volatile_reg = rt1017_sdca_volatile_register, + .max_register = RT1017_MAX_REG_NUM, + .reg_defaults = rt1017_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1017_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists + * port = 1 for AMP playback + * port = 2 for IV capture + */ + prop->source_ports = BIT(2); /* BITMAP: 00000100 */ + prop->sink_ports = BIT(1); /* BITMAP: 00000010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 64; + + return 0; +} + +static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (rt1017->hw_init) + return 0; + + if (rt1017->first_hw_init) { + regcache_cache_only(rt1017->regmap, false); + regcache_cache_bypass(rt1017->regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + /* sw reset */ + regmap_write(rt1017->regmap, 0xc000, 0x02); + + /* initial settings - blind write */ + regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write, + ARRAY_SIZE(rt1017_blind_write)); + + if (rt1017->first_hw_init) { + regcache_cache_bypass(rt1017->regmap, false); + regcache_mark_dirty(rt1017->regmap); + } else + rt1017->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt1017->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "hw_init complete\n"); + return 0; +} + +static int rt1017_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt1017->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1017_sdca_io_init(&slave->dev, slave); +} + +static const char * const rt1017_rx_data_ch_select[] = { + "Bypass", + "CN1", + "CN2", + "CN3", + "CN4", + "(1+2)/2", + "(1+3)/2", + "(1+4)/2", + "(2+3)/2", + "(2+4)/2", + "(3+4)/2", +}; + +static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), + 0, rt1017_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1017_sdca_controls[] = { + /* UDMPU Cluster Selection */ + SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1017_sto_dac = + SOC_DAPM_SINGLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1), + 0, 1, 1); + +static int rt1017_sdca_pde23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + default: + break; + } + return 0; +} + +static int rt1017_sdca_classd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1, + RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG); + regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10); + break; + default: + break; + } + + return 0; +} + +static int rt1017_sdca_feedback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0, + rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Digital Interface */ + SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac), + + /* Output Lines */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPO"), + + SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0, + rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("I Gen"), + SND_SOC_DAPM_SIGGEN("V Gen"), +}; + +static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = { + + { "DAC", "Switch", "DP1RX" }, + { "CLASS D", NULL, "DAC" }, + { "CLASS D", NULL, "PDE23" }, + { "SPO", NULL, "CLASS D" }, + + { "I Sense", NULL, "I Gen" }, + { "V Sense", NULL, "V Gen" }, + { "I Sense", NULL, "PDE23" }, + { "V Sense", NULL, "PDE23" }, + { "DP2TX", NULL, "I Sense" }, + { "DP2TX", NULL, "V Sense" }, +}; + +static struct sdw_slave_ops rt1017_sdca_slave_ops = { + .read_prop = rt1017_sdca_read_prop, + .update_status = rt1017_sdca_update_status, +}; + +static int rt1017_sdca_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static void rt1017_sdca_component_remove(struct snd_soc_component *component) +{ + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1017->regmap, true); +} + +static const struct snd_soc_component_driver soc_sdca_component_rt1017 = { + .probe = rt1017_sdca_component_probe, + .remove = rt1017_sdca_component_remove, + .controls = rt1017_sdca_controls, + .num_controls = ARRAY_SIZE(rt1017_sdca_controls), + .dapm_widgets = rt1017_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets), + .dapm_routes = rt1017_sdca_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes), + .endianness = 1, +}; + +static int rt1017_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt1017_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + int retval, port, num_channels, ch_mask; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt1017->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + num_channels = params_channels(params); + ch_mask = (1 << num_channels) - 1; + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = num_channels; + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + port_config.ch_mask = ch_mask; + port_config.num = port; + + dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n", + params_rate(params), num_channels, snd_pcm_format_width(params_format(params)), + direction, ch_mask, port); + + retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT1017_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT1017_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT1017_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT1017_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1017->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream); + return 0; +} + +static const struct snd_soc_dai_ops rt1017_sdca_ops = { + .hw_params = rt1017_sdca_pcm_hw_params, + .hw_free = rt1017_sdca_pcm_hw_free, + .set_stream = rt1017_sdca_set_sdw_stream, + .shutdown = rt1017_sdca_shutdown, +}; + +#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver rt1017_sdca_dai[] = { + { + .name = "rt1017-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .ops = &rt1017_sdca_ops, + }, +}; + +static int rt1017_sdca_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017; + int ret; + + rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL); + if (!rt1017) + return -ENOMEM; + + dev_set_drvdata(dev, rt1017); + rt1017->sdw_slave = slave; + rt1017->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1017->hw_init = false; + rt1017->first_hw_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_sdca_component_rt1017, + rt1017_sdca_dai, + ARRAY_SIZE(rt1017_sdca_dai)); + + return ret; +} + +static int rt1017_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt1017_sdca_init(&slave->dev, regmap, slave); +} + +static int rt1017_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (rt1017->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + +static const struct sdw_device_id rt1017_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id); + +static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (!rt1017->hw_init) + return 0; + + regcache_cache_only(rt1017->regmap, true); + + return 0; +} + +#define RT1017_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1017->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1017_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt1017->regmap, false); + regcache_sync(rt1017->regmap); + + return 0; +} + +static const struct dev_pm_ops rt1017_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt1017_sdca_sdw_driver = { + .driver = { + .name = "rt1017-sdca", + .owner = THIS_MODULE, + .pm = &rt1017_sdca_pm, + }, + .probe = rt1017_sdca_sdw_probe, + .remove = rt1017_sdca_sdw_remove, + .ops = &rt1017_sdca_slave_ops, + .id_table = rt1017_sdca_id, +}; +module_sdw_driver(rt1017_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW"); +MODULE_AUTHOR("Derek Fang "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h new file mode 100644 index 000000000000..5968b9a7d124 --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2023 Realtek Semiconductor Corp. + */ + +#ifndef __RT1017_SDW_H__ +#define __RT1017_SDW_H__ + +#include +#include +#include +#include +#include + +/* RT1017 SDCA Control - function number */ +#define FUNC_NUM_SMART_AMP 0x04 + +/* RT1017 SDCA entity */ +#define RT1017_SDCA_ENT_PDE23 0x31 +#define RT1017_SDCA_ENT_PDE22 0x33 +#define RT1017_SDCA_ENT_CS21 0x21 +#define RT1017_SDCA_ENT_SAPU29 0x29 +#define RT1017_SDCA_ENT_XU22 0x22 +#define RT1017_SDCA_ENT_FU 0x03 +#define RT1017_SDCA_ENT_UDMPU21 0x02 + +/* RT1017 SDCA control */ +#define RT1017_SDCA_CTL_FS_INDEX 0x10 +#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1017_SDCA_CTL_PROT_STAT 0x11 +#define RT1017_SDCA_CTL_BYPASS 0x01 +#define RT1017_SDCA_CTL_FU_MUTE 0x01 +#define RT1017_SDCA_CTL_FU_VOLUME 0x02 +#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10 + + +#define RT1017_CLASSD_INT_1 0xd300 +#define RT1017_PWM_TRIM_1 0xd370 + + +#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK (0x3 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE (0x2 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG (0x0 << 2) + +enum { + RT1017_SDCA_RATE_44100HZ = 0x8, + RT1017_SDCA_RATE_48000HZ = 0x9, + RT1017_SDCA_RATE_96000HZ = 0xb, + RT1017_SDCA_RATE_192000HZ = 0xd, +}; + +struct rt1017_sdca_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; +}; + +static const struct reg_default rt1017_sdca_reg_defaults[] = { + { 0x3206, 0x00 }, + { 0xc001, 0x43 }, + { 0xc030, 0x54 }, + { 0xc104, 0x8a }, + { 0xc10b, 0x2f }, + { 0xc10c, 0x2f }, + { 0xc110, 0x49 }, + { 0xc112, 0x10 }, + { 0xc300, 0xff }, + { 0xc301, 0xdd }, + { 0xc318, 0x40 }, + { 0xc325, 0x00 }, + { 0xc326, 0x00 }, + { 0xc327, 0x00 }, + { 0xc328, 0x02 }, + { 0xc331, 0xb2 }, + { 0xc340, 0x02 }, + { 0xc350, 0x21 }, + { 0xc500, 0x00 }, + { 0xc502, 0x00 }, + { 0xc504, 0x3f }, + { 0xc507, 0x1f }, + { 0xc509, 0x1f }, + { 0xc510, 0x40 }, + { 0xc512, 0x00 }, + { 0xc518, 0x02 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc520, 0x00 }, + { 0xc540, 0x80 }, + { 0xc541, 0x00 }, + { 0xc542, 0x0a }, + { 0xc550, 0x80 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc600, 0x10 }, + { 0xc602, 0x83 }, + { 0xc612, 0x40 }, + { 0xc622, 0x40 }, + { 0xc632, 0x40 }, + { 0xc642, 0x40 }, + { 0xc651, 0x00 }, + { 0xca00, 0xc1 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x51 }, + { 0xca0b, 0xeb }, + { 0xca0c, 0x85 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x10 }, + { 0xca10, 0x62 }, + { 0xca11, 0x4d }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xcb00, 0x10 }, + { 0xcc00, 0x10 }, + { 0xcc02, 0x0b }, + { 0xd017, 0x09 }, + { 0xd01a, 0x00 }, + { 0xd01b, 0x00 }, + { 0xd01c, 0x00 }, + { 0xd101, 0xa0 }, + { 0xd20c, 0x14 }, + { 0xd300, 0x0f }, + { 0xd370, 0x18 }, + { 0xd500, 0x00 }, + { 0xd545, 0x0b }, + { 0xd546, 0xf9 }, + { 0xd547, 0xb2 }, + { 0xd548, 0xa9 }, + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x00 }, + { 0xd5a7, 0x00 }, + { 0xd5a8, 0x00 }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x00 }, + { 0xd5ac, 0x00 }, + { 0xd5ad, 0x00 }, + { 0xda04, 0x03 }, + { 0xda05, 0x33 }, + { 0xda06, 0x33 }, + { 0xda07, 0x33 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda0c, 0x00 }, + { 0xda0d, 0x01 }, + { 0xda0e, 0x5d }, + { 0xda0f, 0x86 }, + { 0xda11, 0x20 }, + { 0xda12, 0x00 }, + { 0xda13, 0x00 }, + { 0xda14, 0x00 }, + { 0xda16, 0x7f }, + { 0xda17, 0xff }, + { 0xda18, 0xff }, + { 0xda19, 0xff }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x01 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x01 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0xff }, + { 0xdb14, 0x00 }, + + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + +static const struct reg_default rt1017_sdca_mbq_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_VOLUME, 0x01), 0x00 }, +}; + +#endif /* __RT1017_SDW_H__ */ -- cgit v1.2.3 From df8d014edd646692302f3e8ef0bd63a041f4547f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 25 Jul 2023 20:09:17 +0800 Subject: ASoC: cs42l51: change cs42l51_of_match to static cs42l51_of_match is only used in cs42l51-i2c.c now, change it to static. Signed-off-by: Yang Yingliang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230725120917.513064-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index e7db7bcd0296..5ed2ef83dcdb 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,7 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); -const struct of_device_id cs42l51_of_match[] = { +static const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", }, { } }; -- cgit v1.2.3 From 5bdeb6f5c7b94f653183f08eca8a08022b2efac6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 25 Jul 2023 13:49:56 +0300 Subject: Documentation: core-api: Drop :export: for int_log.h The :export: keyword makes sense only for C-files, where EXPORT_SYMBOL() might appear. Otherwise kernel-doc may not produce anything out of this file. Reported-by: Stephen Rothwell Fixes: f97fa3dcb2db ("lib/math: Move dvb_math.c into lib/math/int_log.c") Signed-off-by: Andy Shevchenko Reviewed-by: Randy Dunlap Acked-by: Jonathan Corbet Link: https://lore.kernel.org/r/20230725104956.47806-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/core-api/kernel-api.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index a526fbe06f86..ae92a2571388 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -166,7 +166,6 @@ Integer log and power Functions ------------------------------- .. kernel-doc:: include/linux/int_log.h - :export: .. kernel-doc:: lib/math/int_pow.c :export: -- cgit v1.2.3 From faafd6ca7e6e7100d21d3f43ec17674f36c9f843 Mon Sep 17 00:00:00 2001 From: Sumit Gupta Date: Wed, 21 Jun 2023 19:14:00 +0530 Subject: memory: tegra: make icc_set_bw return zero if BWMGR not supported Return zero from icc_set_bw() to MC client driver if MRQ_BWMGR_INT is not supported by the BPMP-FW. Currently, 'EINVAL' is returned which causes error message in client drivers even when the platform doesn't support scaling. Fixes: 9365bf006f53 ("PCI: tegra194: Add interconnect support in Tegra234") Signed-off-by: Sumit Gupta Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20230621134400.23070-5-sumitg@nvidia.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra234.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c index 4469430aa5fb..8fb83b39f5f5 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -827,7 +827,7 @@ static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst) return 0; if (!mc->bwmgr_mrq_supported) - return -EINVAL; + return 0; if (!mc->bpmp) { dev_err(mc->dev, "BPMP reference NULL\n"); @@ -874,7 +874,7 @@ static int tegra234_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, struct tegra_mc *mc = icc_provider_to_tegra_mc(p); if (!mc->bwmgr_mrq_supported) - return -EINVAL; + return 0; if (node->id == TEGRA_ICC_MC_CPU_CLUSTER0 || node->id == TEGRA_ICC_MC_CPU_CLUSTER1 || -- cgit v1.2.3 From aa6fde93f3a49e42c0fe0490d7f3711bac0d162e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 17 Jul 2023 12:50:02 -1000 Subject: workqueue: Scale up wq_cpu_intensive_thresh_us if BogoMIPS is below 4000 wq_cpu_intensive_thresh_us is used to detect CPU-hogging per-cpu work items. Once detected, they're excluded from concurrency management to prevent them from blocking other per-cpu work items. If CONFIG_WQ_CPU_INTENSIVE_REPORT is enabled, repeat offenders are also reported so that the code can be updated. The default threshold is 10ms which is long enough to do fair bit of work on modern CPUs while short enough to be usually not noticeable. This unfortunately leads to a lot of, arguable spurious, detections on very slow CPUs. Using the same threshold across CPUs whose performance levels may be apart by multiple levels of magnitude doesn't make whole lot of sense. This patch scales up wq_cpu_intensive_thresh_us upto 1 second when BogoMIPS is below 4000. This is obviously very inaccurate but it doesn't have to be accurate to be useful. The mechanism is still useful when the threshold is fully scaled up and the benefits of reports are usually shared with everyone regardless of who's reporting, so as long as there are sufficient number of fast machines reporting, we don't lose much. Some (or is it all?) ARM CPUs systemtically report significantly lower BogoMIPS. While this doesn't break anything, given how widespread ARM CPUs are, it's at least a missed opportunity and it probably would be a good idea to teach workqueue about it. Signed-off-by: Tejun Heo Reported-and-Tested-by: Geert Uytterhoeven --- kernel/workqueue.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 02a8f402eeb5..800b4208dba9 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "workqueue_internal.h" @@ -338,8 +339,10 @@ static cpumask_var_t *wq_numa_possible_cpumask; * Per-cpu work items which run for longer than the following threshold are * automatically considered CPU intensive and excluded from concurrency * management to prevent them from noticeably delaying other per-cpu work items. + * ULONG_MAX indicates that the user hasn't overridden it with a boot parameter. + * The actual value is initialized in wq_cpu_intensive_thresh_init(). */ -static unsigned long wq_cpu_intensive_thresh_us = 10000; +static unsigned long wq_cpu_intensive_thresh_us = ULONG_MAX; module_param_named(cpu_intensive_thresh_us, wq_cpu_intensive_thresh_us, ulong, 0644); static bool wq_disable_numa; @@ -6513,6 +6516,42 @@ void __init workqueue_init_early(void) !system_freezable_power_efficient_wq); } +static void __init wq_cpu_intensive_thresh_init(void) +{ + unsigned long thresh; + unsigned long bogo; + + /* if the user set it to a specific value, keep it */ + if (wq_cpu_intensive_thresh_us != ULONG_MAX) + return; + + /* + * The default of 10ms is derived from the fact that most modern (as of + * 2023) processors can do a lot in 10ms and that it's just below what + * most consider human-perceivable. However, the kernel also runs on a + * lot slower CPUs including microcontrollers where the threshold is way + * too low. + * + * Let's scale up the threshold upto 1 second if BogoMips is below 4000. + * This is by no means accurate but it doesn't have to be. The mechanism + * is still useful even when the threshold is fully scaled up. Also, as + * the reports would usually be applicable to everyone, some machines + * operating on longer thresholds won't significantly diminish their + * usefulness. + */ + thresh = 10 * USEC_PER_MSEC; + + /* see init/calibrate.c for lpj -> BogoMIPS calculation */ + bogo = max_t(unsigned long, loops_per_jiffy / 500000 * HZ, 1); + if (bogo < 4000) + thresh = min_t(unsigned long, thresh * 4000 / bogo, USEC_PER_SEC); + + pr_debug("wq_cpu_intensive_thresh: lpj=%lu BogoMIPS=%lu thresh_us=%lu\n", + loops_per_jiffy, bogo, thresh); + + wq_cpu_intensive_thresh_us = thresh; +} + /** * workqueue_init - bring workqueue subsystem fully online * @@ -6528,6 +6567,8 @@ void __init workqueue_init(void) struct worker_pool *pool; int cpu, bkt; + wq_cpu_intensive_thresh_init(); + /* * It'd be simpler to initialize NUMA in workqueue_init_early() but * CPU to node mapping may not be available that early on some -- cgit v1.2.3 From f2c67a3e60d1071b65848efaa8c3b66c363dd025 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 25 Jul 2023 10:42:05 +0200 Subject: bpf: Disable preemption in bpf_perf_event_output The nesting protection in bpf_perf_event_output relies on disabled preemption, which is guaranteed for kprobes and tracepoints. However bpf_perf_event_output can be also called from uprobes context through bpf_prog_run_array_sleepable function which disables migration, but keeps preemption enabled. This can cause task to be preempted by another one inside the nesting protection and lead eventually to two tasks using same perf_sample_data buffer and cause crashes like: kernel tried to execute NX-protected page - exploit attempt? (uid: 0) BUG: unable to handle page fault for address: ffffffff82be3eea ... Call Trace: ? __die+0x1f/0x70 ? page_fault_oops+0x176/0x4d0 ? exc_page_fault+0x132/0x230 ? asm_exc_page_fault+0x22/0x30 ? perf_output_sample+0x12b/0x910 ? perf_event_output+0xd0/0x1d0 ? bpf_perf_event_output+0x162/0x1d0 ? bpf_prog_c6271286d9a4c938_krava1+0x76/0x87 ? __uprobe_perf_func+0x12b/0x540 ? uprobe_dispatcher+0x2c4/0x430 ? uprobe_notify_resume+0x2da/0xce0 ? atomic_notifier_call_chain+0x7b/0x110 ? exit_to_user_mode_prepare+0x13e/0x290 ? irqentry_exit_to_user_mode+0x5/0x30 ? asm_exc_int3+0x35/0x40 Fixing this by disabling preemption in bpf_perf_event_output. Cc: stable@vger.kernel.org Fixes: 8c7dcb84e3b7 ("bpf: implement sleepable uprobes by chaining gps") Acked-by: Hou Tao Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230725084206.580930-2-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/trace/bpf_trace.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 5f2dcabad202..bf18a53731b0 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -661,8 +661,7 @@ static DEFINE_PER_CPU(int, bpf_trace_nest_level); BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, u64, flags, void *, data, u64, size) { - struct bpf_trace_sample_data *sds = this_cpu_ptr(&bpf_trace_sds); - int nest_level = this_cpu_inc_return(bpf_trace_nest_level); + struct bpf_trace_sample_data *sds; struct perf_raw_record raw = { .frag = { .size = size, @@ -670,7 +669,11 @@ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, }, }; struct perf_sample_data *sd; - int err; + int nest_level, err; + + preempt_disable(); + sds = this_cpu_ptr(&bpf_trace_sds); + nest_level = this_cpu_inc_return(bpf_trace_nest_level); if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(sds->sds))) { err = -EBUSY; @@ -688,9 +691,9 @@ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, perf_sample_save_raw_data(sd, &raw); err = __bpf_perf_event_output(regs, map, flags, sd); - out: this_cpu_dec(bpf_trace_nest_level); + preempt_enable(); return err; } -- cgit v1.2.3 From d62cc390c2e99ae267ffe4b8d7e2e08b6c758c32 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 25 Jul 2023 10:42:06 +0200 Subject: bpf: Disable preemption in bpf_event_output We received report [1] of kernel crash, which is caused by using nesting protection without disabled preemption. The bpf_event_output can be called by programs executed by bpf_prog_run_array_cg function that disabled migration but keeps preemption enabled. This can cause task to be preempted by another one inside the nesting protection and lead eventually to two tasks using same perf_sample_data buffer and cause crashes like: BUG: kernel NULL pointer dereference, address: 0000000000000001 #PF: supervisor instruction fetch in kernel mode #PF: error_code(0x0010) - not-present page ... ? perf_output_sample+0x12a/0x9a0 ? finish_task_switch.isra.0+0x81/0x280 ? perf_event_output+0x66/0xa0 ? bpf_event_output+0x13a/0x190 ? bpf_event_output_data+0x22/0x40 ? bpf_prog_dfc84bbde731b257_cil_sock4_connect+0x40a/0xacb ? xa_load+0x87/0xe0 ? __cgroup_bpf_run_filter_sock_addr+0xc1/0x1a0 ? release_sock+0x3e/0x90 ? sk_setsockopt+0x1a1/0x12f0 ? udp_pre_connect+0x36/0x50 ? inet_dgram_connect+0x93/0xa0 ? __sys_connect+0xb4/0xe0 ? udp_setsockopt+0x27/0x40 ? __pfx_udp_push_pending_frames+0x10/0x10 ? __sys_setsockopt+0xdf/0x1a0 ? __x64_sys_connect+0xf/0x20 ? do_syscall_64+0x3a/0x90 ? entry_SYSCALL_64_after_hwframe+0x72/0xdc Fixing this by disabling preemption in bpf_event_output. [1] https://github.com/cilium/cilium/issues/26756 Cc: stable@vger.kernel.org Reported-by: Oleg "livelace" Popov Closes: https://github.com/cilium/cilium/issues/26756 Fixes: 2a916f2f546c ("bpf: Use migrate_disable/enable in array macros and cgroup/lirc code.") Acked-by: Hou Tao Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230725084206.580930-3-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/trace/bpf_trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index bf18a53731b0..bd1a42b23f3f 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -718,7 +718,6 @@ static DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_misc_sds); u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy) { - int nest_level = this_cpu_inc_return(bpf_event_output_nest_level); struct perf_raw_frag frag = { .copy = ctx_copy, .size = ctx_size, @@ -735,8 +734,12 @@ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, }; struct perf_sample_data *sd; struct pt_regs *regs; + int nest_level; u64 ret; + preempt_disable(); + nest_level = this_cpu_inc_return(bpf_event_output_nest_level); + if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(bpf_misc_sds.sds))) { ret = -EBUSY; goto out; @@ -751,6 +754,7 @@ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, ret = __bpf_perf_event_output(regs, map, flags, sd); out: this_cpu_dec(bpf_event_output_nest_level); + preempt_enable(); return ret; } -- cgit v1.2.3 From e65851989001c0c9ba9177564b13b38201c0854c Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Mon, 24 Jul 2023 16:51:56 +0200 Subject: scsi: zfcp: Defer fc_rport blocking until after ADISC response Storage devices are free to send RSCNs, e.g. for internal state changes. If this happens on all connected paths, zfcp risks temporarily losing all paths at the same time. This has strong requirements on multipath configuration such as "no_path_retry queue". Avoid such situations by deferring fc_rport blocking until after the ADISC response, when any actual state change of the remote port became clear. The already existing port recovery triggers explicitly block the fc_rport. The triggers are: on ADISC reject or timeout (typical cable pull case), and on ADISC indicating that the remote port has changed its WWPN or the port is meanwhile no longer open. As a side effect, this also removes a confusing direct function call to another work item function zfcp_scsi_rport_work() instead of scheduling that other work item. It was probably done that way to have the rport block side effect immediate and synchronous to the caller. Fixes: a2fa0aede07c ("[SCSI] zfcp: Block FC transport rports early on errors") Cc: stable@vger.kernel.org #v2.6.30+ Reviewed-by: Benjamin Block Reviewed-by: Fedor Loshakov Signed-off-by: Steffen Maier Link: https://lore.kernel.org/r/20230724145156.3920244-1-maier@linux.ibm.com Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_fc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index f21307537829..4f0d0e55f0d4 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -534,8 +534,7 @@ static void zfcp_fc_adisc_handler(void *data) /* re-init to undo drop from zfcp_fc_adisc() */ port->d_id = ntoh24(adisc_resp->adisc_port_id); - /* port is good, unblock rport without going through erp */ - zfcp_scsi_schedule_rport_register(port); + /* port is still good, nothing to do */ out: atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); put_device(&port->dev); @@ -595,9 +594,6 @@ void zfcp_fc_link_test_work(struct work_struct *work) int retval; set_worker_desc("zadisc%16llx", port->wwpn); /* < WORKER_DESC_LEN=24 */ - get_device(&port->dev); - port->rport_task = RPORT_DEL; - zfcp_scsi_rport_work(&port->rport_work); /* only issue one test command at one time per port */ if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) -- cgit v1.2.3 From d4e0265345778c623d1fe619075b677731847c34 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 25 Jul 2023 20:57:06 +0800 Subject: scsi: pm80xx: Fix error return code in pm8001_pci_probe() If pm8001_init_sas_add() fails, return error code in pm8001_pci_probe(). Fixes: 14a8f116cdc0 ("scsi: pm80xx: Add GET_NVMD timeout during probe") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230725125706.566990-1-yangyingliang@huawei.com Reviewed-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 2e886c1d867d..4995e1ef4e0e 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1181,7 +1181,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm80xx_set_thermal_config(pm8001_ha); } - if (pm8001_init_sas_add(pm8001_ha)) + rc = pm8001_init_sas_add(pm8001_ha); + if (rc) goto err_out_shost; /* phy setting support for motherboard controller */ rc = pm8001_configure_phy_settings(pm8001_ha); -- cgit v1.2.3 From d265ebe41c911314bd273c218a37088835959fa1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 20 Jul 2023 18:14:44 +0300 Subject: Revert "wifi: ath11k: Enable threaded NAPI" This reverts commit 13aa2fb692d3717767303817f35b3e650109add3. This commit broke QCN9074 initialisation: [ 358.960477] ath11k_pci 0000:04:00.0: ce desc not available for wmi command 36866 [ 358.960481] ath11k_pci 0000:04:00.0: failed to send WMI_STA_POWERSAVE_PARAM_CMDID [ 358.960484] ath11k_pci 0000:04:00.0: could not set uapsd params -105 As there's no fix available let's just revert it to get QCN9074 working again. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217536 Signed-off-by: Kalle Valo Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230720151444.2016637-1-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/ahb.c | 1 - drivers/net/wireless/ath/ath11k/pcic.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 1cebba7889d7..139da578831a 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -376,7 +376,6 @@ static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab) struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; if (!irq_grp->napi_enabled) { - dev_set_threaded(&irq_grp->napi_ndev, true); napi_enable(&irq_grp->napi); irq_grp->napi_enabled = true; } diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index c899616fbee4..c63083633b37 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -466,7 +466,6 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab) struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; if (!irq_grp->napi_enabled) { - dev_set_threaded(&irq_grp->napi_ndev, true); napi_enable(&irq_grp->napi); irq_grp->napi_enabled = true; } -- cgit v1.2.3 From fd7f08d92fcd7cc3eca0dd6c853f722a4c6176df Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 23 Jul 2023 23:10:43 +0300 Subject: wifi: cfg80211: Fix return value in scan logic The reporter noticed a warning when running iwlwifi: WARNING: CPU: 8 PID: 659 at mm/page_alloc.c:4453 __alloc_pages+0x329/0x340 As cfg80211_parse_colocated_ap() is not expected to return a negative value return 0 and not a negative value if cfg80211_calc_short_ssid() fails. Fixes: c8cb5b854b40f ("nl80211/cfg80211: support 6 GHz scanning") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217675 Signed-off-by: Ilan Peer Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230723201043.3007430-1-ilan.peer@intel.com --- net/wireless/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 8bf00caf5d29..0cf1ce7b6934 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -657,7 +657,7 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp); if (ret) - return ret; + return 0; for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data, ies->len) { -- cgit v1.2.3 From a1ce186db7f0e449f35d12fb55ae0da2a1b400e2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:08:23 +0300 Subject: Revert "wifi: ath6k: silence false positive -Wno-dangling-pointer warning on GCC 12" This reverts commit bd1d129daa3ede265a880e2c6a7f91eab0f4dc62. The dangling-pointer warnings were disabled kernel-wide by commit 49beadbd47c2 ("gcc-12: disable '-Wdangling-pointer' warning for now") for v5.19. So this hack in ath6kl is not needed anymore. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724100823.2948804-1-kvalo@kernel.org --- drivers/net/wireless/ath/ath6kl/Makefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index a75bfa9fd1cf..dc2b3b46781e 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -36,11 +36,6 @@ ath6kl_core-y += wmi.o ath6kl_core-y += core.o ath6kl_core-y += recovery.o -# FIXME: temporarily silence -Wdangling-pointer on non W=1+ builds -ifndef KBUILD_EXTRA_WARN -CFLAGS_htc_mbox.o += $(call cc-disable-warning, dangling-pointer) -endif - ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath6kl_core-$(CONFIG_ATH6KL_TRACING) += trace.o -- cgit v1.2.3 From 96839282edc28996809b2101afef8ae971b9dad7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:39 +0300 Subject: MAINTAINERS: wifi: rtw88: change Ping as the maintainer Yan-Hsuan has been away since 2021 and Ping has been the de facto maintainer the past year, actively reviewing patches and doing all other maintainer duties. So fix the MAINTAINERS file to show the current situation. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-2-kvalo@kernel.org --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 42e78a696be6..58b399c7fb5e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17969,7 +17969,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g F: drivers/net/wireless/realtek/rtlwifi/ REALTEK WIRELESS DRIVER (rtw88) -M: Yan-Hsuan Chuang +M: Ping-Ke Shih L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/realtek/rtw88/ -- cgit v1.2.3 From 25700d4916fefd27f83b933149c4da3d32db8585 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:40 +0300 Subject: MAINTAINERS: wifi: atmel: mark as orphan Last activity from Simon is from 2005 so mark the driver is orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-3-kvalo@kernel.org --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 58b399c7fb5e..35de04265644 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3260,9 +3260,8 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml F: drivers/input/touchscreen/atmel_mxt_ts.c ATMEL WIRELESS DRIVER -M: Simon Kelley L: linux-wireless@vger.kernel.org -S: Maintained +S: Orphan W: http://www.thekelleys.org.uk/atmel W: http://atmelwlandriver.sourceforge.net/ F: drivers/net/wireless/atmel/atmel* -- cgit v1.2.3 From 74b81eac2dda55584aa6102feb920142ab08721a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:41 +0300 Subject: MAINTAINERS: wifi: mark cw1200 as orphan Last activity from Solomon is from 2013 so mark the driver orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-4-kvalo@kernel.org --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 35de04265644..fc3c83c42efb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5451,8 +5451,7 @@ F: Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml F: drivers/net/can/ctucanfd/ CW1200 WLAN driver -M: Solomon Peachy -S: Maintained +S: Orphan F: drivers/net/wireless/st/cw1200/ CX18 VIDEO4LINUX DRIVER -- cgit v1.2.3 From e76983151dc66717e43c2a77abcfdb36318d2255 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:42 +0300 Subject: MAINTAINERS: wifi: mark ar5523 as orphan Last activity from Pontus for this driver is from 2013 so mark the driver orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-5-kvalo@kernel.org --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fc3c83c42efb..3792e3de4822 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21884,9 +21884,8 @@ S: Maintained F: drivers/usb/misc/apple-mfi-fastcharge.c USB AR5523 WIRELESS DRIVER -M: Pontus Fuchs L: linux-wireless@vger.kernel.org -S: Maintained +S: Orphan F: drivers/net/wireless/ath/ar5523/ USB ATTACHED SCSI -- cgit v1.2.3 From bc5dee3ce7c06d2c3d7a3b135a24f85de45a8362 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:43 +0300 Subject: MAINTAINERS: wifi: mark rndis_wlan as orphan Last activity from Jussi for this driver is from 2013 so mark the driver orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-6-kvalo@kernel.org --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3792e3de4822..3d890a82149a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22162,9 +22162,8 @@ F: drivers/usb/gadget/legacy/webcam.c F: include/uapi/linux/usb/g_uvc.h USB WIRELESS RNDIS DRIVER (rndis_wlan) -M: Jussi Kivilinna L: linux-wireless@vger.kernel.org -S: Maintained +S: Orphan F: drivers/net/wireless/legacy/rndis_wlan.c USB XHCI DRIVER -- cgit v1.2.3 From 0566ec90515c50352442db467d2a8c8950d35dc9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:44 +0300 Subject: MAINTAINERS: wifi: mark wl3501 as orphan There's no maintainer for this driver so mark it as orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-7-kvalo@kernel.org --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3d890a82149a..9ad555da5e36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22938,7 +22938,7 @@ F: drivers/input/misc/wistron_btns.c WL3501 WIRELESS PCMCIA CARD DRIVER L: linux-wireless@vger.kernel.org -S: Odd fixes +S: Orphan F: drivers/net/wireless/legacy/wl3501* WMI BINARY MOF DRIVER -- cgit v1.2.3 From c1e0a70de12dea642c696a81fd1104f5377fb203 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:45 +0300 Subject: MAINTAINERS: wifi: mark zd1211rw as orphan Last activity from Ulrich is from 2007 so mark the driver orphan. Remove the zd1211-devs list, I doubt anyone uses it anymore. The webpage seems to be down so remove that as well. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-8-kvalo@kernel.org --- MAINTAINERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9ad555da5e36..2f988aa03f2e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23509,11 +23509,8 @@ S: Maintained F: mm/zbud.c ZD1211RW WIRELESS DRIVER -M: Ulrich Kunitz L: linux-wireless@vger.kernel.org -L: zd1211-devs@lists.sourceforge.net (subscribers-only) -S: Maintained -W: http://zd1211.ath.cx/wiki/DriverRewrite +S: Orphan F: drivers/net/wireless/zydas/zd1211rw/ ZD1301 MEDIA DRIVER -- cgit v1.2.3 From 3ccbc99c152fded21ff3661d7685095e14065e96 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:46 +0300 Subject: MAINTAINERS: wifi: mark b43 as orphan There's no maintainer for b43 so mark it as orphan. Signed-off-by: Kalle Valo Acked-by: Larry Finger Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-9-kvalo@kernel.org --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2f988aa03f2e..eccc3794e6e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3391,7 +3391,7 @@ F: drivers/media/radio/radio-aztech* B43 WIRELESS DRIVER L: linux-wireless@vger.kernel.org L: b43-dev@lists.infradead.org -S: Odd Fixes +S: Orphan W: https://wireless.wiki.kernel.org/en/users/Drivers/b43 F: drivers/net/wireless/broadcom/b43/ -- cgit v1.2.3 From cc326aae03c37d393e8dfba950caa33493dcdfad Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 24 Jul 2023 13:45:47 +0300 Subject: MAINTAINERS: wifi: mark mlw8k as orphan Last activity from Lennert is from 2012 so mark the driver as orphan. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230724104547.3061709-10-kvalo@kernel.org --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index eccc3794e6e2..ab9a31f4954c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12583,9 +12583,8 @@ S: Odd Fixes F: drivers/net/wireless/marvell/mwifiex/ MARVELL MWL8K WIRELESS DRIVER -M: Lennert Buytenhek L: linux-wireless@vger.kernel.org -S: Odd Fixes +S: Orphan F: drivers/net/wireless/marvell/mwl8k.c MARVELL NAND CONTROLLER DRIVER -- cgit v1.2.3 From 456b5e85d8a56e5563573b10e0840c7ae59373da Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 25 Jul 2023 12:42:48 +0300 Subject: MAINTAINERS: add Jeff as ath10k, ath11k and ath12k maintainer Jeff will now start maintaining these drivers together with me. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230725094248.3205486-1-kvalo@kernel.org --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ab9a31f4954c..71edae152e3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17430,6 +17430,7 @@ F: drivers/media/tuners/qt1010* QUALCOMM ATH12K WIRELESS DRIVER M: Kalle Valo +M: Jeff Johnson L: ath12k@lists.infradead.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git @@ -17437,6 +17438,7 @@ F: drivers/net/wireless/ath/ath12k/ QUALCOMM ATHEROS ATH10K WIRELESS DRIVER M: Kalle Valo +M: Jeff Johnson L: ath10k@lists.infradead.org S: Supported W: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k @@ -17446,6 +17448,7 @@ F: drivers/net/wireless/ath/ath10k/ QUALCOMM ATHEROS ATH11K WIRELESS DRIVER M: Kalle Valo +M: Jeff Johnson L: ath11k@lists.infradead.org S: Supported W: https://wireless.wiki.kernel.org/en/users/Drivers/ath11k -- cgit v1.2.3 From f6500ec12c1ec745fbec20fd4734b832bbfd4aac Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Tue, 25 Jul 2023 22:08:38 +0000 Subject: ASoC: intel: avs: refactor strncpy usage in topology `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2]. There are some hopes that someday the `strncpy` api could be ripped out due to the vast number of suitable replacements (strscpy, strscpy_pad, strtomem, strtomem_pad, strlcpy) [1]. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230725-sound-soc-intel-avs-remove-deprecated-strncpy-v1-1-6357a1f8e9cf@google.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/topology.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index cdb4ec500261..45d0eb2a8e71 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1388,12 +1388,12 @@ static int avs_route_load(struct snd_soc_component *comp, int index, port = __ffs(mach->mach_params.i2s_link_mask); snprintf(buf, len, route->source, port); - strncpy((char *)route->source, buf, len); + strscpy((char *)route->source, buf, len); snprintf(buf, len, route->sink, port); - strncpy((char *)route->sink, buf, len); + strscpy((char *)route->sink, buf, len); if (route->control) { snprintf(buf, len, route->control, port); - strncpy((char *)route->control, buf, len); + strscpy((char *)route->control, buf, len); } } -- cgit v1.2.3 From 8744776363c370b0eeb0ed50cb0212d7826639b7 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 26 Jul 2023 09:10:51 +0000 Subject: ASoC: rt1316: fix key tone missing This patch adds a control that there are three options to control the digital volume output. The user could select "immediately" to make volume updates immediately and avoid key tone missing issues. In default, the driver selects that the volume update when a zero-crossing with a soft ramp. Signed-off-by: Shuming Fan Reported-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230726091051.658754-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 721821d9e9af..10a53c8d4874 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -424,6 +424,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum, SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0, rt1316_rx_data_ch_select); +static const char * const rt1316_dac_output_vol_select[] = { + "immediately", + "zero crossing", + "zero crossing with soft ramp", +}; + +static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum, + 0xc010, 6, rt1316_dac_output_vol_select); + static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* I2S Data Channel Selection */ @@ -442,6 +451,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* IV mixer Control */ SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1), SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1), + + /* DAC Output Volume Control */ + SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum), }; static const struct snd_kcontrol_new rt1316_sto_dac = -- cgit v1.2.3 From c17bd30d0ba5ca59266771cdfc387f26271a7042 Mon Sep 17 00:00:00 2001 From: YingKun Meng Date: Wed, 26 Jul 2023 19:05:16 +0800 Subject: ASoC: loongson: drop of_match_ptr for OF device id The ASoC Sound Card driver can be compile tested with !CONFIG_OF making 'loongson_asoc_dt_ids' unused: sound/soc/loongson/loongson_card.c:200:34: warning: unused variable 'loongson_asoc_dt_ids' [-Wunused-const-variable] As krzysztof advice, we drop of_match_ptr so the device id can also be used on ACPI. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307242008.xqdjgk04-lkp@intel.com Fixes: d24028606e76 ("ASoC: loongson: Add Loongson ASoC Sound Card Support") Signed-off-by: YingKun Meng Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230726110516.703342-1-mengyingkun@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index 9ded16329747..406ee8db1a3c 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -208,7 +208,7 @@ static struct platform_driver loongson_audio_driver = { .driver = { .name = "loongson-asoc-card", .pm = &snd_soc_pm_ops, - .of_match_table = of_match_ptr(loongson_asoc_dt_ids), + .of_match_table = loongson_asoc_dt_ids, }, }; module_platform_driver(loongson_audio_driver); -- cgit v1.2.3 From c5097b9869a136349d8404715dc8aabb7570a762 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 6 Jul 2023 10:26:10 +0200 Subject: Revert "PCI: dwc: Wait for link up only if link is started" This reverts commit da56a1bfbab55189595e588f1d984bdfb5cf5924. Bjorn Andersson, Fabio Estevam, Xiaolei Wang, and Jon Hunter reported that da56a1bfbab5 ("PCI: dwc: Wait for link up only if link is started") broke controller probing by returning an error in case the link does not come up during host initialisation, for example when the slot is empty. As explained in commit 886a9c134755 ("PCI: dwc: Move link handling into common code") and as indicated by the comment "Ignore errors, the link may come up later" in the code, waiting for link up and ignoring errors is the intended behaviour: Let's standardize this to succeed as there are usecases where devices (and the link) appear later even without hotplug. For example, a reconfigured FPGA device. Reverting the offending commit specifically fixes a regression on Qualcomm platforms like the Lenovo ThinkPad X13s which no longer reach the interconnect sync state if a slot does not have a device populated (e.g. an optional modem). Note that enabling asynchronous probing by default as was done for Qualcomm platforms by commit c0e1eb441b1d ("PCI: qcom: Enable async probe by default"), should take care of any related boot time concerns. Finally, note that the intel-gw driver is the only driver currently not providing a .start_link() callback and instead starts the link in its .host_init() callback, which may avoid an additional one-second timeout during probe by making the link-up wait conditional. If anyone cares, that can be done in a follow-up patch with a proper motivation. [bhelgaas: add Fabio Estevam, Xiaolei Wang, Jon Hunter reports] Fixes: da56a1bfbab5 ("PCI: dwc: Wait for link up only if link is started") Link: https://lore.kernel.org/r/20230706082610.26584-1-johan+linaro@kernel.org Reported-by: Bjorn Andersson Signed-off-by: Johan Hovold Reported-by: Fabio Estevam Link: https://lore.kernel.org/r/20230704122635.1362156-1-festevam@gmail.com/ Reported-by: Xiaolei Wang Link: https://lore.kernel.org/r/20230705010624.3912934-1-xiaolei.wang@windriver.com/ Reported-by: Jon Hunter Link: https://lore.kernel.org/r/6ca287a1-6c7c-7b90-9022-9e73fb82b564@nvidia.com Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Cc: Sajid Dalvi Cc: Ajay Agarwal --- drivers/pci/controller/dwc/pcie-designware-host.c | 13 ++++--------- drivers/pci/controller/dwc/pcie-designware.c | 20 +++++++------------- drivers/pci/controller/dwc/pcie-designware.h | 1 - 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index cf61733bf78d..9952057c8819 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -485,20 +485,15 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (ret) goto err_remove_edma; - if (dw_pcie_link_up(pci)) { - dw_pcie_print_link_status(pci); - } else { + if (!dw_pcie_link_up(pci)) { ret = dw_pcie_start_link(pci); if (ret) goto err_remove_edma; - - if (pci->ops && pci->ops->start_link) { - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_stop_link; - } } + /* Ignore errors, the link may come up later */ + dw_pcie_wait_for_link(pci); + bridge->sysdata = pp; ret = pci_host_probe(bridge); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c87848cd8686..1f2ee71da4da 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -644,20 +644,9 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index) dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0); } -void dw_pcie_print_link_status(struct dw_pcie *pci) -{ - u32 offset, val; - - offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); - val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); - - dev_info(pci->dev, "PCIe Gen.%u x%u link up\n", - FIELD_GET(PCI_EXP_LNKSTA_CLS, val), - FIELD_GET(PCI_EXP_LNKSTA_NLW, val)); -} - int dw_pcie_wait_for_link(struct dw_pcie *pci) { + u32 offset, val; int retries; /* Check if the link is up or not */ @@ -673,7 +662,12 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci) return -ETIMEDOUT; } - dw_pcie_print_link_status(pci); + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); + + dev_info(pci->dev, "PCIe Gen.%u x%u link up\n", + FIELD_GET(PCI_EXP_LNKSTA_CLS, val), + FIELD_GET(PCI_EXP_LNKSTA_NLW, val)); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 615660640801..79713ce075cc 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -429,7 +429,6 @@ void dw_pcie_setup(struct dw_pcie *pci); void dw_pcie_iatu_detect(struct dw_pcie *pci); int dw_pcie_edma_detect(struct dw_pcie *pci); void dw_pcie_edma_remove(struct dw_pcie *pci); -void dw_pcie_print_link_status(struct dw_pcie *pci); static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) { -- cgit v1.2.3 From ce92232614a5fb16992de8eb85bba7cb90772a1f Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:23 +0100 Subject: KVM: arm64: Factor out code for checking (h)VHE mode into a macro The code for checking whether the kernel is in (h)VHE mode is repeated, and will be needed again in future patches. Factor it out in a macro. No functional change intended. No change in emitted assembly code intended. Signed-off-by: Fuad Tabba Link: https://lore.kernel.org/kvmarm/20230724123829.2929609-3-tabba@google.com/ Reviewed-by: Marc Zyngier Signed-off-by: Oliver Upton --- arch/arm64/include/asm/el2_setup.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index 8e5ffb58f83e..16d3bafa715d 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -31,6 +31,13 @@ .Lskip_hcrx_\@: .endm +/* Check if running in host at EL2 mode, i.e., (h)VHE. Jump to fail if not. */ +.macro __check_hvhe fail, tmp + mrs \tmp, hcr_el2 + and \tmp, \tmp, #HCR_E2H + cbz \tmp, \fail +.endm + /* * Allow Non-secure EL1 and EL0 to access physical timer and counter. * This is not necessary for VHE, since the host kernel runs in EL2, @@ -43,9 +50,7 @@ */ .macro __init_el2_timers mov x0, #3 // Enable EL1 physical timers - mrs x1, hcr_el2 - and x1, x1, #HCR_E2H - cbz x1, .LnVHE_\@ + __check_hvhe .LnVHE_\@, x1 lsl x0, x0, #10 .LnVHE_\@: msr cnthctl_el2, x0 @@ -139,9 +144,7 @@ /* Coprocessor traps */ .macro __init_el2_cptr - mrs x1, hcr_el2 - and x1, x1, #HCR_E2H - cbz x1, .LnVHE_\@ + __check_hvhe .LnVHE_\@, x1 mov x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN) b .Lset_cptr_\@ .LnVHE_\@: @@ -269,9 +272,7 @@ .Linit_sve_\@: /* SVE register access */ mrs x0, cptr_el2 // Disable SVE traps - mrs x1, hcr_el2 - and x1, x1, #HCR_E2H - cbz x1, .Lcptr_nvhe_\@ + __check_hvhe .Lcptr_nvhe_\@, x1 // VHE case orr x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN) -- cgit v1.2.3 From 45a3681a10ff1732fcd7a177fbf1f9ceeaffd7c9 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:24 +0100 Subject: KVM: arm64: Use the appropriate feature trap register for SVE at EL2 setup Use the architectural feature trap/control register that corresponds to the current KVM mode, i.e., CPTR_EL2 or CPACR_EL1, when setting up SVE feature traps. Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-4-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/el2_setup.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index 16d3bafa715d..41c5b02f38c5 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -146,11 +146,12 @@ .macro __init_el2_cptr __check_hvhe .LnVHE_\@, x1 mov x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN) - b .Lset_cptr_\@ + msr cpacr_el1, x0 + b .Lskip_set_cptr_\@ .LnVHE_\@: mov x0, #0x33ff -.Lset_cptr_\@: msr cptr_el2, x0 // Disable copro. traps to EL2 +.Lskip_set_cptr_\@: .endm /* Disable any fine grained traps */ @@ -271,17 +272,19 @@ check_override id_aa64pfr0, ID_AA64PFR0_EL1_SVE_SHIFT, .Linit_sve_\@, .Lskip_sve_\@, x1, x2 .Linit_sve_\@: /* SVE register access */ - mrs x0, cptr_el2 // Disable SVE traps __check_hvhe .Lcptr_nvhe_\@, x1 - // VHE case + // (h)VHE case + mrs x0, cpacr_el1 // Disable SVE traps orr x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN) - b .Lset_cptr_\@ + msr cpacr_el1, x0 + b .Lskip_set_cptr_\@ .Lcptr_nvhe_\@: // nVHE case + mrs x0, cptr_el2 // Disable SVE traps bic x0, x0, #CPTR_EL2_TZ -.Lset_cptr_\@: msr cptr_el2, x0 +.Lskip_set_cptr_\@: isb mov x1, #ZCR_ELx_LEN_MASK // SVE: Enable full vector msr_s SYS_ZCR_EL2, x1 // length for EL1. -- cgit v1.2.3 From 380624d4358b0150804d279c20632555e453bc1f Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:25 +0100 Subject: KVM: arm64: Disable SME traps for (h)VHE at setup Ensure that SME traps are disabled for (h)VHE when setting up EL2, as they are for nVHE. Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-5-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/el2_setup.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index 41c5b02f38c5..b7afaa026842 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -293,9 +293,19 @@ check_override id_aa64pfr1, ID_AA64PFR1_EL1_SME_SHIFT, .Linit_sme_\@, .Lskip_sme_\@, x1, x2 .Linit_sme_\@: /* SME register access and priority mapping */ + __check_hvhe .Lcptr_nvhe_sme_\@, x1 + + // (h)VHE case + mrs x0, cpacr_el1 // Disable SME traps + orr x0, x0, #(CPACR_EL1_SMEN_EL0EN | CPACR_EL1_SMEN_EL1EN) + msr cpacr_el1, x0 + b .Lskip_set_cptr_sme_\@ + +.Lcptr_nvhe_sme_\@: // nVHE case mrs x0, cptr_el2 // Disable SME traps bic x0, x0, #CPTR_EL2_TSM msr cptr_el2, x0 +.Lskip_set_cptr_sme_\@: isb mrs x1, sctlr_el2 -- cgit v1.2.3 From 90ae31c65d5afdd0864017c9354247ddb601917f Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:26 +0100 Subject: KVM: arm64: Helper to write to appropriate feature trap register based on mode Factor out the code that decides whether to write to the feature trap registers, CPTR_EL2 or CPACR_EL1, based on the KVM mode, i.e., (h)VHE or nVHE. This function will be used in the subsequent patch. No functional change intended. Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-6-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_emulate.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index efc0b45d79c3..f5941f6dce49 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -571,6 +571,14 @@ static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature) return test_bit(feature, vcpu->arch.features); } +static __always_inline void kvm_write_cptr_el2(u64 val) +{ + if (has_vhe() || has_hvhe()) + write_sysreg(val, cpacr_el1); + else + write_sysreg(val, cptr_el2); +} + static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu) { u64 val; @@ -597,9 +605,6 @@ static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu) { u64 val = kvm_get_reset_cptr_el2(vcpu); - if (has_vhe() || has_hvhe()) - write_sysreg(val, cpacr_el1); - else - write_sysreg(val, cptr_el2); + kvm_write_cptr_el2(val); } #endif /* __ARM64_KVM_EMULATE_H__ */ -- cgit v1.2.3 From a9626099a51f697939d35983b92a9384a4c4a676 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:27 +0100 Subject: KVM: arm64: Use the appropriate feature trap register when activating traps Instead of writing directly to cptr_el2, use the helper that selects which feature trap register to write to based on the KVM mode. Fixes: 75c76ab5a641 ("KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration") Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-7-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index 0a6271052def..e89a23153e85 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -63,7 +63,7 @@ static void __activate_traps(struct kvm_vcpu *vcpu) __activate_traps_fpsimd32(vcpu); } - write_sysreg(val, cptr_el2); + kvm_write_cptr_el2(val); write_sysreg(__this_cpu_read(kvm_hyp_vector), vbar_el2); if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) { -- cgit v1.2.3 From 7af0d5e50006614cbf313373df708df79d9f4657 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:28 +0100 Subject: KVM: arm64: Fix resetting SVE trap values on reset for hVHE Ensure that SVE traps are disabled for hVHE, if the FPSIMD state isn't owned by the guest, when getting the reset value for the architectural feature control register. Fixes: 75c76ab5a641 ("KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration") Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-8-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_emulate.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index f5941f6dce49..adfb7d0ac55b 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -588,6 +588,10 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu) CPACR_EL1_ZEN_EL1EN); } else if (has_hvhe()) { val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN); + + if (!vcpu_has_sve(vcpu) || + (vcpu->arch.fp_state != FP_STATE_GUEST_OWNED)) + val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN; } else { val = CPTR_NVHE_EL2_RES1; -- cgit v1.2.3 From 375110ab51dec5dcd077b8fa95075b2c67499119 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 24 Jul 2023 13:38:29 +0100 Subject: KVM: arm64: Fix resetting SME trap values on reset for (h)VHE Ensure that SME traps are disabled for (h)VHE when getting the reset value for the architectural feature control register. Fixes: 75c76ab5a641 ("KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration") Signed-off-by: Fuad Tabba Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724123829.2929609-9-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_emulate.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index adfb7d0ac55b..3d6725ff0bf6 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -586,12 +586,16 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu) if (has_vhe()) { val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN | CPACR_EL1_ZEN_EL1EN); + if (cpus_have_final_cap(ARM64_SME)) + val |= CPACR_EL1_SMEN_EL1EN; } else if (has_hvhe()) { val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN); if (!vcpu_has_sve(vcpu) || (vcpu->arch.fp_state != FP_STATE_GUEST_OWNED)) val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN; + if (cpus_have_final_cap(ARM64_SME)) + val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN; } else { val = CPTR_NVHE_EL2_RES1; -- cgit v1.2.3 From 01b94b0f3922039f7d3e0d1eeb33b8891746b65f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Jul 2023 14:18:42 +0200 Subject: KVM: arm64: fix __kvm_host_psci_cpu_entry() prototype The kvm_host_psci_cpu_entry() function was renamed in order to add a wrapper around it, but the prototype did not change, so now the missing-prototype warning came back in W=1 builds: arch/arm64/kvm/hyp/nvhe/psci-relay.c:203:28: error: no previous prototype for function '__kvm_host_psci_cpu_entry' [-Werror,-Wmissing-prototypes] asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on) Fixes: dcf89d1111995 ("KVM: arm64: Add missing BTI instructions") Signed-off-by: Arnd Bergmann Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724121850.1386668-1-arnd@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_asm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 7d170aaa2db4..24e28bb2d95b 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -278,7 +278,7 @@ asmlinkage void __noreturn hyp_panic_bad_stack(void); asmlinkage void kvm_unexpected_el2_exception(void); struct kvm_cpu_context; void handle_trap(struct kvm_cpu_context *host_ctxt); -asmlinkage void __noreturn kvm_host_psci_cpu_entry(bool is_cpu_on); +asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on); void __noreturn __pkvm_init_finalise(void); void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc); void kvm_patch_vector_branch(struct alt_instr *alt, -- cgit v1.2.3 From 5befe22b3eebd07b334b2917f6d14ce7ee4c8404 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 26 Jul 2023 18:16:20 +0200 Subject: ASoC: fsl: fsl_qmc_audio: Fix snd_pcm_format_t values handling Running sparse on fsl_qmc_audio (make C=1) raises the following warnings: fsl_qmc_audio.c:387:26: warning: restricted snd_pcm_format_t degrades to integer fsl_qmc_audio.c:389:59: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:389:59: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:389:59: got unsigned int [assigned] i fsl_qmc_audio.c:564:26: warning: restricted snd_pcm_format_t degrades to integer fsl_qmc_audio.c:569:50: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:569:50: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:569:50: got int [assigned] i fsl_qmc_audio.c:573:62: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:573:62: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:573:62: got int [assigned] i These warnings are due to snd_pcm_format_t values handling done in the driver. Some macros and functions exist to handle safely these values. Use dedicated macros and functions to remove these warnings. Fixes: 075c7125b11c ("ASoC: fsl: Add support for QMC audio") Signed-off-by: Herve Codina Link: https://lore.kernel.org/r/20230726161620.495298-1-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 7cbb8e4758cc..56d6b0b039a2 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); unsigned int channels = params_channels(params); unsigned int slot_width; + snd_pcm_format_t format; struct snd_mask f_new; - unsigned int i; if (!channels || channels > nb_ts) { dev_err(qmc_dai->dev, "channels %u not supported\n", @@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, slot_width = (nb_ts / channels) * 8; snd_mask_none(&f_new); - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(f_old, i)) { - if (snd_pcm_format_physical_width(i) <= slot_width) - snd_mask_set(&f_new, i); + pcm_for_each_format(format) { + if (snd_mask_test_format(f_old, format)) { + if (snd_pcm_format_physical_width(format) <= slot_width) + snd_mask_set_format(&f_new, format); } } @@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = { static u64 qmc_audio_formats(u8 nb_ts) { - u64 formats; - unsigned int chan_width; unsigned int format_width; - int i; + unsigned int chan_width; + snd_pcm_format_t format; + u64 formats_mask; if (!nb_ts) return 0; - formats = 0; + formats_mask = 0; chan_width = nb_ts * 8; - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { + pcm_for_each_format(format) { /* * Support format other than little-endian (ie big-endian or * without endianness such as 8bit formats) */ - if (snd_pcm_format_little_endian(i) == 1) + if (snd_pcm_format_little_endian(format) == 1) continue; /* Support physical width multiple of 8bit */ - format_width = snd_pcm_format_physical_width(i); + format_width = snd_pcm_format_physical_width(format); if (format_width == 0 || format_width % 8) continue; @@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts) if (format_width > chan_width || chan_width % format_width) continue; - formats |= (1ULL << i); + formats_mask |= pcm_format_to_bits(format); } - return formats; + return formats_mask; } static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, -- cgit v1.2.3 From aeb660171b0663847fa04806a96302ac6112ad26 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Tue, 4 Jul 2023 15:06:40 +0800 Subject: net/mlx5e: fix double free in macsec_fs_tx_create_crypto_table_groups In function macsec_fs_tx_create_crypto_table_groups(), when the ft->g memory is successfully allocated but the 'in' memory fails to be allocated, the memory pointed to by ft->g is released once. And in function macsec_fs_tx_create(), macsec_fs_tx_destroy() is called to release the memory pointed to by ft->g again. This will cause double free problem. Fixes: e467b283ffd5 ("net/mlx5e: Add MACsec TX steering rules") Signed-off-by: Zhengchao Shao Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c index 7fc901a6ec5f..414e28584881 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c @@ -161,6 +161,7 @@ static int macsec_fs_tx_create_crypto_table_groups(struct mlx5e_flow_table *ft) if (!in) { kfree(ft->g); + ft->g = NULL; return -ENOMEM; } -- cgit v1.2.3 From 5dd77585dd9d0e03dd1bceb95f0269a7eaf6b936 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Wed, 5 Jul 2023 20:15:27 +0800 Subject: net/mlx5: DR, fix memory leak in mlx5dr_cmd_create_reformat_ctx when mlx5_cmd_exec failed in mlx5dr_cmd_create_reformat_ctx, the memory pointed by 'in' is not released, which will cause memory leak. Move memory release after mlx5_cmd_exec. Fixes: 1d9186476e12 ("net/mlx5: DR, Add direct rule command utilities") Signed-off-by: Zhengchao Shao Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c index 7491911ebcb5..8c2a34a0d6be 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c @@ -564,11 +564,12 @@ int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); if (err) - return err; + goto err_free_in; *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id); - kvfree(in); +err_free_in: + kvfree(in); return err; } -- cgit v1.2.3 From c6cf0b6097bf1bf1b2a89b521e9ecd26b581a93a Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Sat, 8 Jul 2023 15:13:07 +0800 Subject: net/mlx5: fix potential memory leak in mlx5e_init_rep_rx The memory pointed to by the priv->rx_res pointer is not freed in the error path of mlx5e_init_rep_rx, which can lead to a memory leak. Fix by freeing the memory in the error path, thereby making the error path identical to mlx5e_cleanup_rep_rx(). Fixes: af8bbf730068 ("net/mlx5e: Convert mlx5e_flow_steering member of mlx5e_priv to pointer") Signed-off-by: Zhengchao Shao Reviewed-by: Simon Horman Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 152b62138450..0b265a3f9b76 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1012,7 +1012,7 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) err = mlx5e_open_drop_rq(priv, &priv->drop_rq); if (err) { mlx5_core_err(mdev, "open drop rq failed, %d\n", err); - return err; + goto err_rx_res_free; } err = mlx5e_rx_res_init(priv->rx_res, priv->mdev, 0, @@ -1046,6 +1046,7 @@ err_destroy_rx_res: mlx5e_rx_res_destroy(priv->rx_res); err_close_drop_rq: mlx5e_close_drop_rq(&priv->drop_rq); +err_rx_res_free: mlx5e_rx_res_free(priv->rx_res); priv->rx_res = NULL; err_free_fs: -- cgit v1.2.3 From e5bcb7564d3bd0c88613c76963c5349be9c511c5 Mon Sep 17 00:00:00 2001 From: Yuanjun Gong Date: Tue, 25 Jul 2023 14:56:55 +0800 Subject: net/mlx5e: fix return value check in mlx5e_ipsec_remove_trailer() mlx5e_ipsec_remove_trailer() should return an error code if function pskb_trim() returns an unexpected value. Fixes: 2ac9cfe78223 ("net/mlx5e: IPSec, Add Innova IPSec offload TX data path") Signed-off-by: Yuanjun Gong Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c index eab5bc718771..8d995e304869 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c @@ -58,7 +58,9 @@ static int mlx5e_ipsec_remove_trailer(struct sk_buff *skb, struct xfrm_state *x) trailer_len = alen + plen + 2; - pskb_trim(skb, skb->len - trailer_len); + ret = pskb_trim(skb, skb->len - trailer_len); + if (unlikely(ret)) + return ret; if (skb->protocol == htons(ETH_P_IP)) { ipv4hdr->tot_len = htons(ntohs(ipv4hdr->tot_len) - trailer_len); ip_send_check(ipv4hdr); -- cgit v1.2.3 From 0507f2c8be0d345fe7014147c027cea6dc1c00a4 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Mon, 3 Jul 2023 17:34:44 +0300 Subject: net/mlx5: Honor user input for migratable port fn attr Currently, whenever a user is setting migratable port fn attr, the driver is always turn migratable capability on. Fix it by honor the user input Fixes: e5b9642a33be ("net/mlx5: E-Switch, Implement devlink port function cmds to control migratable") Signed-off-by: Shay Drory Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index bdfe609cc9ec..93b2b94d41cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -4196,7 +4196,7 @@ int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable, } hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); - MLX5_SET(cmd_hca_cap_2, hca_caps, migratable, 1); + MLX5_SET(cmd_hca_cap_2, hca_caps, migratable, enable); err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport->vport, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE2); -- cgit v1.2.3 From 93a331939d1d1c6c3422bc09ec43cac658594b34 Mon Sep 17 00:00:00 2001 From: Chris Mi Date: Thu, 29 Jun 2023 11:32:03 +0300 Subject: net/mlx5e: Don't hold encap tbl lock if there is no encap action The cited commit holds encap tbl lock unconditionally when setting up dests. But it may cause the following deadlock: PID: 1063722 TASK: ffffa062ca5d0000 CPU: 13 COMMAND: "handler8" #0 [ffffb14de05b7368] __schedule at ffffffffa1d5aa91 #1 [ffffb14de05b7410] schedule at ffffffffa1d5afdb #2 [ffffb14de05b7430] schedule_preempt_disabled at ffffffffa1d5b528 #3 [ffffb14de05b7440] __mutex_lock at ffffffffa1d5d6cb #4 [ffffb14de05b74e8] mutex_lock_nested at ffffffffa1d5ddeb #5 [ffffb14de05b74f8] mlx5e_tc_tun_encap_dests_set at ffffffffc12f2096 [mlx5_core] #6 [ffffb14de05b7568] post_process_attr at ffffffffc12d9fc5 [mlx5_core] #7 [ffffb14de05b75a0] mlx5e_tc_add_fdb_flow at ffffffffc12de877 [mlx5_core] #8 [ffffb14de05b75f0] __mlx5e_add_fdb_flow at ffffffffc12e0eef [mlx5_core] #9 [ffffb14de05b7660] mlx5e_tc_add_flow at ffffffffc12e12f7 [mlx5_core] #10 [ffffb14de05b76b8] mlx5e_configure_flower at ffffffffc12e1686 [mlx5_core] #11 [ffffb14de05b7720] mlx5e_rep_indr_offload at ffffffffc12e3817 [mlx5_core] #12 [ffffb14de05b7730] mlx5e_rep_indr_setup_tc_cb at ffffffffc12e388a [mlx5_core] #13 [ffffb14de05b7740] tc_setup_cb_add at ffffffffa1ab2ba8 #14 [ffffb14de05b77a0] fl_hw_replace_filter at ffffffffc0bdec2f [cls_flower] #15 [ffffb14de05b7868] fl_change at ffffffffc0be6caa [cls_flower] #16 [ffffb14de05b7908] tc_new_tfilter at ffffffffa1ab71f0 [1031218.028143] wait_for_completion+0x24/0x30 [1031218.028589] mlx5e_update_route_decap_flows+0x9a/0x1e0 [mlx5_core] [1031218.029256] mlx5e_tc_fib_event_work+0x1ad/0x300 [mlx5_core] [1031218.029885] process_one_work+0x24e/0x510 Actually no need to hold encap tbl lock if there is no encap action. Fix it by checking if encap action exists or not before holding encap tbl lock. Fixes: 37c3b9fa7ccf ("net/mlx5e: Prevent encap offload when neigh update is running") Signed-off-by: Chris Mi Reviewed-by: Vlad Buslov Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/en/tc_tun_encap.c | 3 --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 21 ++++++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c index f0c3464f037f..0c88cf47af01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c @@ -1030,9 +1030,6 @@ int mlx5e_tc_tun_encap_dests_set(struct mlx5e_priv *priv, int out_index; int err = 0; - if (!mlx5e_is_eswitch_flow(flow)) - return 0; - parse_attr = attr->parse_attr; esw_attr = attr->esw_attr; *vf_tun = false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 8d0a3f69693e..92377632f9e0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1725,6 +1725,19 @@ verify_attr_actions(u32 actions, struct netlink_ext_ack *extack) return 0; } +static bool +has_encap_dests(struct mlx5_flow_attr *attr) +{ + struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr; + int out_index; + + for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) + if (esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) + return true; + + return false; +} + static int post_process_attr(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *attr, @@ -1737,9 +1750,11 @@ post_process_attr(struct mlx5e_tc_flow *flow, if (err) goto err_out; - err = mlx5e_tc_tun_encap_dests_set(flow->priv, flow, attr, extack, &vf_tun); - if (err) - goto err_out; + if (mlx5e_is_eswitch_flow(flow) && has_encap_dests(attr)) { + err = mlx5e_tc_tun_encap_dests_set(flow->priv, flow, attr, extack, &vf_tun); + if (err) + goto err_out; + } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { err = mlx5e_tc_attach_mod_hdr(flow->priv, flow, attr); -- cgit v1.2.3 From 3ec43c1b082a8804472430e1253544d75f4b540e Mon Sep 17 00:00:00 2001 From: Amir Tzin Date: Tue, 30 May 2023 20:11:14 +0300 Subject: net/mlx5e: Fix crash moving to switchdev mode when ntuple offload is set Moving to switchdev mode with ntuple offload on causes the kernel to crash since fs->arfs is freed during nic profile cleanup flow. Ntuple offload is not supported in switchdev mode and it is already unset by mlx5 fix feature ndo in switchdev mode. Verify fs->arfs is valid before disabling it. trace: [] RIP: 0010:_raw_spin_lock_bh+0x17/0x30 [] arfs_del_rules+0x44/0x1a0 [mlx5_core] [] mlx5e_arfs_disable+0xe/0x20 [mlx5_core] [] mlx5e_handle_feature+0x3d/0xb0 [mlx5_core] [] ? __rtnl_unlock+0x25/0x50 [] mlx5e_set_features+0xfe/0x160 [mlx5_core] [] __netdev_update_features+0x278/0xa50 [] ? netdev_run_todo+0x5e/0x2a0 [] netdev_update_features+0x22/0x70 [] ? _cond_resched+0x15/0x30 [] mlx5e_attach_netdev+0x12a/0x1e0 [mlx5_core] [] mlx5e_netdev_attach_profile+0xa1/0xc0 [mlx5_core] [] mlx5e_netdev_change_profile+0x77/0xe0 [mlx5_core] [] mlx5e_vport_rep_load+0x1ed/0x290 [mlx5_core] [] mlx5_esw_offloads_rep_load+0x88/0xd0 [mlx5_core] [] esw_offloads_load_rep.part.38+0x31/0x50 [mlx5_core] [] esw_offloads_enable+0x6c5/0x710 [mlx5_core] [] mlx5_eswitch_enable_locked+0x1bb/0x290 [mlx5_core] [] mlx5_devlink_eswitch_mode_set+0x14f/0x320 [mlx5_core] [] devlink_nl_cmd_eswitch_set_doit+0x94/0x120 [] genl_family_rcv_msg_doit.isra.17+0x113/0x150 [] genl_family_rcv_msg+0xb7/0x170 [] ? devlink_nl_cmd_port_split_doit+0x100/0x100 [] genl_rcv_msg+0x47/0xa0 [] ? genl_family_rcv_msg+0x170/0x170 [] netlink_rcv_skb+0x4c/0x130 [] genl_rcv+0x24/0x40 [] netlink_unicast+0x19a/0x230 [] netlink_sendmsg+0x204/0x3d0 [] sock_sendmsg+0x50/0x60 Fixes: 90b22b9bcd24 ("net/mlx5e: Disable Rx ntuple offload for uplink representor") Signed-off-by: Amir Tzin Reviewed-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 933a7772a7a3..5aa51d74f8b4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -135,6 +135,16 @@ static void arfs_del_rules(struct mlx5e_flow_steering *fs); int mlx5e_arfs_disable(struct mlx5e_flow_steering *fs) { + /* Moving to switchdev mode, fs->arfs is freed by mlx5e_nic_profile + * cleanup_rx callback and it is not recreated when + * mlx5e_uplink_rep_profile is loaded as mlx5e_create_flow_steering() + * is not called by the uplink_rep profile init_rx callback. Thus, if + * ntuple is set, moving to switchdev flow will enter this function + * with fs->arfs nullified. + */ + if (!mlx5e_fs_get_arfs(fs)) + return 0; + arfs_del_rules(fs); return arfs_disable(fs); -- cgit v1.2.3 From d03b6e6f31820b84f7449cca022047f36c42bc3f Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Mon, 3 Jul 2023 08:28:16 +0000 Subject: net/mlx5e: Move representor neigh cleanup to profile cleanup_tx For IP tunnel encapsulation in ECMP (Equal-Cost Multipath) mode, as the flow is duplicated to the peer eswitch, the related neighbour information on the peer uplink representor is created as well. In the cited commit, eswitch devcom unpair is moved to uplink unload API, specifically the profile->cleanup_tx. If there is a encap rule offloaded in ECMP mode, when one eswitch does unpair (because of unloading the driver, for instance), and the peer rule from the peer eswitch is going to be deleted, the use-after-free error is triggered while accessing neigh info, as it is already cleaned up in uplink's profile->disable, which is before its profile->cleanup_tx. To fix this issue, move the neigh cleanup to profile's cleanup_tx callback, and after mlx5e_cleanup_uplink_rep_tx is called. The neigh init is moved to init_tx for symmeter. [ 2453.376299] BUG: KASAN: slab-use-after-free in mlx5e_rep_neigh_entry_release+0x109/0x3a0 [mlx5_core] [ 2453.379125] Read of size 4 at addr ffff888127af9008 by task modprobe/2496 [ 2453.381542] CPU: 7 PID: 2496 Comm: modprobe Tainted: G B 6.4.0-rc7+ #15 [ 2453.383386] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 [ 2453.384335] Call Trace: [ 2453.384625] [ 2453.384891] dump_stack_lvl+0x33/0x50 [ 2453.385285] print_report+0xc2/0x610 [ 2453.385667] ? __virt_addr_valid+0xb1/0x130 [ 2453.386091] ? mlx5e_rep_neigh_entry_release+0x109/0x3a0 [mlx5_core] [ 2453.386757] kasan_report+0xae/0xe0 [ 2453.387123] ? mlx5e_rep_neigh_entry_release+0x109/0x3a0 [mlx5_core] [ 2453.387798] mlx5e_rep_neigh_entry_release+0x109/0x3a0 [mlx5_core] [ 2453.388465] mlx5e_rep_encap_entry_detach+0xa6/0xe0 [mlx5_core] [ 2453.389111] mlx5e_encap_dealloc+0xa7/0x100 [mlx5_core] [ 2453.389706] mlx5e_tc_tun_encap_dests_unset+0x61/0xb0 [mlx5_core] [ 2453.390361] mlx5_free_flow_attr_actions+0x11e/0x340 [mlx5_core] [ 2453.391015] ? complete_all+0x43/0xd0 [ 2453.391398] ? free_flow_post_acts+0x38/0x120 [mlx5_core] [ 2453.392004] mlx5e_tc_del_fdb_flow+0x4ae/0x690 [mlx5_core] [ 2453.392618] mlx5e_tc_del_fdb_peers_flow+0x308/0x370 [mlx5_core] [ 2453.393276] mlx5e_tc_clean_fdb_peer_flows+0xf5/0x140 [mlx5_core] [ 2453.393925] mlx5_esw_offloads_unpair+0x86/0x540 [mlx5_core] [ 2453.394546] ? mlx5_esw_offloads_set_ns_peer.isra.0+0x180/0x180 [mlx5_core] [ 2453.395268] ? down_write+0xaa/0x100 [ 2453.395652] mlx5_esw_offloads_devcom_event+0x203/0x530 [mlx5_core] [ 2453.396317] mlx5_devcom_send_event+0xbb/0x190 [mlx5_core] [ 2453.396917] mlx5_esw_offloads_devcom_cleanup+0xb0/0xd0 [mlx5_core] [ 2453.397582] mlx5e_tc_esw_cleanup+0x42/0x120 [mlx5_core] [ 2453.398182] mlx5e_rep_tc_cleanup+0x15/0x30 [mlx5_core] [ 2453.398768] mlx5e_cleanup_rep_tx+0x6c/0x80 [mlx5_core] [ 2453.399367] mlx5e_detach_netdev+0xee/0x120 [mlx5_core] [ 2453.399957] mlx5e_netdev_change_profile+0x84/0x170 [mlx5_core] [ 2453.400598] mlx5e_vport_rep_unload+0xe0/0xf0 [mlx5_core] [ 2453.403781] mlx5_eswitch_unregister_vport_reps+0x15e/0x190 [mlx5_core] [ 2453.404479] ? mlx5_eswitch_register_vport_reps+0x200/0x200 [mlx5_core] [ 2453.405170] ? up_write+0x39/0x60 [ 2453.405529] ? kernfs_remove_by_name_ns+0xb7/0xe0 [ 2453.405985] auxiliary_bus_remove+0x2e/0x40 [ 2453.406405] device_release_driver_internal+0x243/0x2d0 [ 2453.406900] ? kobject_put+0x42/0x2d0 [ 2453.407284] bus_remove_device+0x128/0x1d0 [ 2453.407687] device_del+0x240/0x550 [ 2453.408053] ? waiting_for_supplier_show+0xe0/0xe0 [ 2453.408511] ? kobject_put+0xfa/0x2d0 [ 2453.408889] ? __kmem_cache_free+0x14d/0x280 [ 2453.409310] mlx5_rescan_drivers_locked.part.0+0xcd/0x2b0 [mlx5_core] [ 2453.409973] mlx5_unregister_device+0x40/0x50 [mlx5_core] [ 2453.410561] mlx5_uninit_one+0x3d/0x110 [mlx5_core] [ 2453.411111] remove_one+0x89/0x130 [mlx5_core] [ 2453.411628] pci_device_remove+0x59/0xf0 [ 2453.412026] device_release_driver_internal+0x243/0x2d0 [ 2453.412511] ? parse_option_str+0x14/0x90 [ 2453.412915] driver_detach+0x7b/0xf0 [ 2453.413289] bus_remove_driver+0xb5/0x160 [ 2453.413685] pci_unregister_driver+0x3f/0xf0 [ 2453.414104] mlx5_cleanup+0xc/0x20 [mlx5_core] Fixes: 2be5bd42a5bb ("net/mlx5: Handle pairing of E-switch via uplink un/load APIs") Signed-off-by: Jianbo Liu Reviewed-by: Vlad Buslov Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 0b265a3f9b76..99b3843396f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1160,6 +1160,10 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv) return err; } + err = mlx5e_rep_neigh_init(rpriv); + if (err) + goto err_neigh_init; + if (rpriv->rep->vport == MLX5_VPORT_UPLINK) { err = mlx5e_init_uplink_rep_tx(rpriv); if (err) @@ -1176,6 +1180,8 @@ err_ht_init: if (rpriv->rep->vport == MLX5_VPORT_UPLINK) mlx5e_cleanup_uplink_rep_tx(rpriv); err_init_tx: + mlx5e_rep_neigh_cleanup(rpriv); +err_neigh_init: mlx5e_destroy_tises(priv); return err; } @@ -1189,22 +1195,17 @@ static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv) if (rpriv->rep->vport == MLX5_VPORT_UPLINK) mlx5e_cleanup_uplink_rep_tx(rpriv); + mlx5e_rep_neigh_cleanup(rpriv); mlx5e_destroy_tises(priv); } static void mlx5e_rep_enable(struct mlx5e_priv *priv) { - struct mlx5e_rep_priv *rpriv = priv->ppriv; - mlx5e_set_netdev_mtu_boundaries(priv); - mlx5e_rep_neigh_init(rpriv); } static void mlx5e_rep_disable(struct mlx5e_priv *priv) { - struct mlx5e_rep_priv *rpriv = priv->ppriv; - - mlx5e_rep_neigh_cleanup(rpriv); } static int mlx5e_update_rep_rx(struct mlx5e_priv *priv) @@ -1254,7 +1255,6 @@ static int uplink_rep_async_event(struct notifier_block *nb, unsigned long event static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv) { - struct mlx5e_rep_priv *rpriv = priv->ppriv; struct net_device *netdev = priv->netdev; struct mlx5_core_dev *mdev = priv->mdev; u16 max_mtu; @@ -1276,7 +1276,6 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv) mlx5_notifier_register(mdev, &priv->events_nb); mlx5e_dcbnl_initialize(priv); mlx5e_dcbnl_init_app(priv); - mlx5e_rep_neigh_init(rpriv); mlx5e_rep_bridge_init(priv); netdev->wanted_features |= NETIF_F_HW_TC; @@ -1291,7 +1290,6 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv) static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv) { - struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_core_dev *mdev = priv->mdev; rtnl_lock(); @@ -1301,7 +1299,6 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv) rtnl_unlock(); mlx5e_rep_bridge_cleanup(priv); - mlx5e_rep_neigh_cleanup(rpriv); mlx5e_dcbnl_delete_app(priv); mlx5_notifier_unregister(mdev, &priv->events_nb); mlx5e_rep_tc_disable(priv); -- cgit v1.2.3 From e0f52298fee449fec37e3e3c32df60008b509b16 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Tue, 18 Jul 2023 11:13:33 +0300 Subject: net/mlx5e: xsk: Fix invalid buffer access for legacy rq The below crash can be encountered when using xdpsock in rx mode for legacy rq: the buffer gets released in the XDP_REDIRECT path, and then once again in the driver. This fix sets the flag to avoid releasing on the driver side. XSK handling of buffers for legacy rq was relying on the caller to set the skip release flag. But the referenced fix started using fragment counts for pages instead of the skip flag. Crash log: general protection fault, probably for non-canonical address 0xffff8881217e3a: 0000 [#1] SMP CPU: 0 PID: 14 Comm: ksoftirqd/0 Not tainted 6.5.0-rc1+ #31 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 RIP: 0010:bpf_prog_03b13f331978c78c+0xf/0x28 Code: ... RSP: 0018:ffff88810082fc98 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff888138404901 RCX: c0ffffc900027cbc RDX: ffffffffa000b514 RSI: 00ffff8881217e32 RDI: ffff888138404901 RBP: ffff88810082fc98 R08: 0000000000091100 R09: 0000000000000006 R10: 0000000000000800 R11: 0000000000000800 R12: ffffc9000027a000 R13: ffff8881217e2dc0 R14: ffff8881217e2910 R15: ffff8881217e2f00 FS: 0000000000000000(0000) GS:ffff88852c800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000564cb2e2cde0 CR3: 000000010e603004 CR4: 0000000000370eb0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ? die_addr+0x32/0x80 ? exc_general_protection+0x192/0x390 ? asm_exc_general_protection+0x22/0x30 ? 0xffffffffa000b514 ? bpf_prog_03b13f331978c78c+0xf/0x28 mlx5e_xdp_handle+0x48/0x670 [mlx5_core] ? dev_gro_receive+0x3b5/0x6e0 mlx5e_xsk_skb_from_cqe_linear+0x6e/0x90 [mlx5_core] mlx5e_handle_rx_cqe+0x55/0x100 [mlx5_core] mlx5e_poll_rx_cq+0x87/0x6e0 [mlx5_core] mlx5e_napi_poll+0x45e/0x6b0 [mlx5_core] __napi_poll+0x25/0x1a0 net_rx_action+0x28a/0x300 __do_softirq+0xcd/0x279 ? sort_range+0x20/0x20 run_ksoftirqd+0x1a/0x20 smpboot_thread_fn+0xa2/0x130 kthread+0xc9/0xf0 ? kthread_complete_and_exit+0x20/0x20 ret_from_fork+0x1f/0x30 Modules linked in: mlx5_ib mlx5_core rpcrdma rdma_ucm ib_iser libiscsi scsi_transport_iscsi ib_umad rdma_cm ib_ipoib iw_cm ib_cm ib_uverbs ib_core xt_conntrack xt_MASQUERADE nf_conntrack_netlink nfnetlink xt_addrtype iptable_nat nf_nat br_netfilter overlay zram zsmalloc fuse [last unloaded: mlx5_core] ---[ end trace 0000000000000000 ]--- Fixes: 7abd955a58fb ("net/mlx5e: RX, Fix page_pool page fragment tracking for XDP") Signed-off-by: Dragos Tatulea Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c index d97e6df66f45..b8dd74453655 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c @@ -323,8 +323,11 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq, net_prefetch(mxbuf->xdp.data); prog = rcu_dereference(rq->xdp_prog); - if (likely(prog && mlx5e_xdp_handle(rq, prog, mxbuf))) + if (likely(prog && mlx5e_xdp_handle(rq, prog, mxbuf))) { + if (likely(__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))) + wi->flags |= BIT(MLX5E_WQE_FRAG_SKIP_RELEASE); return NULL; /* page/packet was consumed by XDP */ + } /* XDP_PASS: copy the data from the UMEM to a new SKB. The frame reuse * will be handled by mlx5e_free_rx_wqe. -- cgit v1.2.3 From 39646d9bcd1a65d2396328026626859a1dab59d7 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Mon, 24 Apr 2023 18:19:00 +0300 Subject: net/mlx5e: xsk: Fix crash on regular rq reactivation When the regular rq is reactivated after the XSK socket is closed it could be reading stale cqes which eventually corrupts the rq. This leads to no more traffic being received on the regular rq and a crash on the next close or deactivation of the rq. Kal Cuttler Conely reported this issue as a crash on the release path when the xdpsock sample program is stopped (killed) and restarted in sequence while traffic is running. This patch flushes all cqes when during the rq flush. The cqe flushing is done in the reset state of the rq. mlx5e_rq_to_ready code is moved into the flush function to allow for this. Fixes: 082a9edf12fe ("net/mlx5e: xsk: Flush RQ on XSK activation to save memory") Reported-by: Kal Cutter Conley Closes: https://lore.kernel.org/xdp-newbies/CAHApi-nUAs4TeFWUDV915CZJo07XVg2Vp63-no7UDfj6wur9nQ@mail.gmail.com Signed-off-by: Dragos Tatulea Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 29 ++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index defb1efccb78..1c820119e438 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1036,7 +1036,23 @@ static int mlx5e_modify_rq_state(struct mlx5e_rq *rq, int curr_state, int next_s return err; } -static int mlx5e_rq_to_ready(struct mlx5e_rq *rq, int curr_state) +static void mlx5e_flush_rq_cq(struct mlx5e_rq *rq) +{ + struct mlx5_cqwq *cqwq = &rq->cq.wq; + struct mlx5_cqe64 *cqe; + + if (test_bit(MLX5E_RQ_STATE_MINI_CQE_ENHANCED, &rq->state)) { + while ((cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq))) + mlx5_cqwq_pop(cqwq); + } else { + while ((cqe = mlx5_cqwq_get_cqe(cqwq))) + mlx5_cqwq_pop(cqwq); + } + + mlx5_cqwq_update_db_record(cqwq); +} + +int mlx5e_flush_rq(struct mlx5e_rq *rq, int curr_state) { struct net_device *dev = rq->netdev; int err; @@ -1046,6 +1062,10 @@ static int mlx5e_rq_to_ready(struct mlx5e_rq *rq, int curr_state) netdev_err(dev, "Failed to move rq 0x%x to reset\n", rq->rqn); return err; } + + mlx5e_free_rx_descs(rq); + mlx5e_flush_rq_cq(rq); + err = mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY); if (err) { netdev_err(dev, "Failed to move rq 0x%x to ready\n", rq->rqn); @@ -1055,13 +1075,6 @@ static int mlx5e_rq_to_ready(struct mlx5e_rq *rq, int curr_state) return 0; } -int mlx5e_flush_rq(struct mlx5e_rq *rq, int curr_state) -{ - mlx5e_free_rx_descs(rq); - - return mlx5e_rq_to_ready(rq, curr_state); -} - static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd) { struct mlx5_core_dev *mdev = rq->mdev; -- cgit v1.2.3 From eb02b93aad952008f1692cee5c5b13001e908407 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Tue, 27 Jun 2023 09:26:56 +0200 Subject: net/mlx5: Bridge, set debugfs access right to root-only As suggested during code review set the access rights for bridge 'fdb' debugfs file to root-only. Fixes: 791eb78285e8 ("net/mlx5: Bridge, expose FDB state via debugfs") Reported-by: Jakub Kicinski Link: https://lore.kernel.org/netdev/20230619120515.5045132a@kernel.org/ Signed-off-by: Vlad Buslov Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c index b6a45eff28f5..dbd7cbe6cbf3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c @@ -64,7 +64,7 @@ void mlx5_esw_bridge_debugfs_init(struct net_device *br_netdev, struct mlx5_esw_ bridge->debugfs_dir = debugfs_create_dir(br_netdev->name, bridge->br_offloads->debugfs_root); - debugfs_create_file("fdb", 0444, bridge->debugfs_dir, bridge, + debugfs_create_file("fdb", 0400, bridge->debugfs_dir, bridge, &mlx5_esw_bridge_debugfs_fops); } -- cgit v1.2.3 From 3e4cf1dd2ce413f4be3e2c9062fb470e2ad2be88 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Mon, 8 May 2023 03:36:10 +0000 Subject: net/mlx5e: kTLS, Fix protection domain in use syndrome when devlink reload There are DEK objects cached in DEK pool after kTLS is used, and they are freed only in mlx5e_ktls_cleanup(). mlx5e_destroy_mdev_resources() is called in mlx5e_suspend() to free mdev resources, including protection domain (PD). However, PD is still referenced by the cached DEK objects in this case, because profile->cleanup() (and therefore mlx5e_ktls_cleanup()) is called after mlx5e_suspend() during devlink reload. So the following FW syndrome is generated: mlx5_cmd_out_err:803:(pid 12948): DEALLOC_PD(0x801) op_mod(0x0) failed, status bad resource state(0x9), syndrome (0xef0c8a), err(-22) To avoid this syndrome, move DEK pool destruction to mlx5e_ktls_cleanup_tx(), which is called by profile->cleanup_tx(). And move pool creation to mlx5e_ktls_init_tx() for symmetry. Fixes: f741db1a5171 ("net/mlx5e: kTLS, Improve connection rate by using fast update encryption key") Signed-off-by: Jianbo Liu Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/en_accel/ktls.c | 8 ------ .../ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c | 29 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c index cf704f106b7c..984fa04bd331 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c @@ -188,7 +188,6 @@ static void mlx5e_tls_debugfs_init(struct mlx5e_tls *tls, int mlx5e_ktls_init(struct mlx5e_priv *priv) { - struct mlx5_crypto_dek_pool *dek_pool; struct mlx5e_tls *tls; if (!mlx5e_is_ktls_device(priv->mdev)) @@ -199,12 +198,6 @@ int mlx5e_ktls_init(struct mlx5e_priv *priv) return -ENOMEM; tls->mdev = priv->mdev; - dek_pool = mlx5_crypto_dek_pool_create(priv->mdev, MLX5_ACCEL_OBJ_TLS_KEY); - if (IS_ERR(dek_pool)) { - kfree(tls); - return PTR_ERR(dek_pool); - } - tls->dek_pool = dek_pool; priv->tls = tls; mlx5e_tls_debugfs_init(tls, priv->dfs_root); @@ -222,7 +215,6 @@ void mlx5e_ktls_cleanup(struct mlx5e_priv *priv) debugfs_remove_recursive(tls->debugfs.dfs); tls->debugfs.dfs = NULL; - mlx5_crypto_dek_pool_destroy(tls->dek_pool); kfree(priv->tls); priv->tls = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index efb2cf74ad6a..d61be26a4df1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -908,28 +908,51 @@ static void mlx5e_tls_tx_debugfs_init(struct mlx5e_tls *tls, int mlx5e_ktls_init_tx(struct mlx5e_priv *priv) { + struct mlx5_crypto_dek_pool *dek_pool; struct mlx5e_tls *tls = priv->tls; + int err; + + if (!mlx5e_is_ktls_device(priv->mdev)) + return 0; + + /* DEK pool could be used by either or both of TX and RX. But we have to + * put the creation here to avoid syndrome when doing devlink reload. + */ + dek_pool = mlx5_crypto_dek_pool_create(priv->mdev, MLX5_ACCEL_OBJ_TLS_KEY); + if (IS_ERR(dek_pool)) + return PTR_ERR(dek_pool); + tls->dek_pool = dek_pool; if (!mlx5e_is_ktls_tx(priv->mdev)) return 0; priv->tls->tx_pool = mlx5e_tls_tx_pool_init(priv->mdev, &priv->tls->sw_stats); - if (!priv->tls->tx_pool) - return -ENOMEM; + if (!priv->tls->tx_pool) { + err = -ENOMEM; + goto err_tx_pool_init; + } mlx5e_tls_tx_debugfs_init(tls, tls->debugfs.dfs); return 0; + +err_tx_pool_init: + mlx5_crypto_dek_pool_destroy(dek_pool); + return err; } void mlx5e_ktls_cleanup_tx(struct mlx5e_priv *priv) { if (!mlx5e_is_ktls_tx(priv->mdev)) - return; + goto dek_pool_destroy; debugfs_remove_recursive(priv->tls->debugfs.dfs_tx); priv->tls->debugfs.dfs_tx = NULL; mlx5e_tls_tx_pool_cleanup(priv->tls->tx_pool); priv->tls->tx_pool = NULL; + +dek_pool_destroy: + if (mlx5e_is_ktls_device(priv->mdev)) + mlx5_crypto_dek_pool_destroy(priv->tls->dek_pool); } -- cgit v1.2.3 From 61eab651f6e96791cfad6db45f1107c398699b2d Mon Sep 17 00:00:00 2001 From: Chris Mi Date: Mon, 17 Jul 2023 08:32:51 +0300 Subject: net/mlx5: fs_chains: Fix ft prio if ignore_flow_level is not supported The cited commit sets ft prio to fs_base_prio. But if ignore_flow_level it not supported, ft prio must be set based on tc filter prio. Otherwise, all the ft prio are the same on the same chain. It is invalid if ignore_flow_level is not supported. Fix it by setting ft prio based on tc filter prio and setting fs_base_prio to 0 for fdb. Fixes: 8e80e5648092 ("net/mlx5: fs_chains: Refactor to detach chains from tc usage") Signed-off-by: Chris Mi Reviewed-by: Paul Blakey Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 93b2b94d41cd..bc04abb31f9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1436,7 +1436,6 @@ esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb) esw_init_chains_offload_flags(esw, &attr.flags); attr.ns = MLX5_FLOW_NAMESPACE_FDB; - attr.fs_base_prio = FDB_TC_OFFLOAD; attr.max_grp_num = esw->params.large_group_num; attr.default_ft = miss_fdb; attr.mapping = esw->offloads.reg_c0_obj_pool; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c index db9df9798ffa..a80ecb672f33 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c @@ -178,7 +178,7 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains, if (!mlx5_chains_ignore_flow_level_supported(chains) || (chain == 0 && prio == 1 && level == 0)) { ft_attr.level = chains->fs_base_level; - ft_attr.prio = chains->fs_base_prio; + ft_attr.prio = chains->fs_base_prio + prio - 1; ns = (chains->ns == MLX5_FLOW_NAMESPACE_FDB) ? mlx5_get_fdb_sub_ns(chains->dev, chain) : mlx5_get_flow_namespace(chains->dev, chains->ns); -- cgit v1.2.3 From 62752c0bc67f79f064cbe2605054f99d52809e7b Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 14 Jun 2023 09:03:32 +0300 Subject: net/mlx5: DR, Fix peer domain namespace setting The offending patch is based on the assumption that for PFs, mlx5_get_dev_index() is the same as vhca_id. However, this assumption is wrong in case of DPU (ECPF). Fix it by using vhca_id directly, and switch the array of peers to xarray. Fixes: 6d5b7321d8af ("net/mlx5: DR, handle more than one peer domain") Signed-off-by: Shay Drory Reviewed-by: Yevgeny Kliteynik Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 14 +++++++------- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 2 +- .../ethernet/mellanox/mlx5/core/steering/dr_action.c | 2 +- .../ethernet/mellanox/mlx5/core/steering/dr_domain.c | 19 +++++++++++++------ .../ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c | 7 ++++--- .../ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c | 7 ++++--- .../ethernet/mellanox/mlx5/core/steering/dr_types.h | 2 +- .../net/ethernet/mellanox/mlx5/core/steering/fs_dr.c | 4 ++-- .../net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h | 2 +- 12 files changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index bc04abb31f9c..e59380ee1ead 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2778,9 +2778,9 @@ static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw, struct mlx5_eswitch *peer_esw, bool pair) { - u8 peer_idx = mlx5_get_dev_index(peer_esw->dev); + u16 peer_vhca_id = MLX5_CAP_GEN(peer_esw->dev, vhca_id); + u16 vhca_id = MLX5_CAP_GEN(esw->dev, vhca_id); struct mlx5_flow_root_namespace *peer_ns; - u8 idx = mlx5_get_dev_index(esw->dev); struct mlx5_flow_root_namespace *ns; int err; @@ -2788,18 +2788,18 @@ static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw, ns = esw->dev->priv.steering->fdb_root_ns; if (pair) { - err = mlx5_flow_namespace_set_peer(ns, peer_ns, peer_idx); + err = mlx5_flow_namespace_set_peer(ns, peer_ns, peer_vhca_id); if (err) return err; - err = mlx5_flow_namespace_set_peer(peer_ns, ns, idx); + err = mlx5_flow_namespace_set_peer(peer_ns, ns, vhca_id); if (err) { - mlx5_flow_namespace_set_peer(ns, NULL, peer_idx); + mlx5_flow_namespace_set_peer(ns, NULL, peer_vhca_id); return err; } } else { - mlx5_flow_namespace_set_peer(ns, NULL, peer_idx); - mlx5_flow_namespace_set_peer(peer_ns, NULL, idx); + mlx5_flow_namespace_set_peer(ns, NULL, peer_vhca_id); + mlx5_flow_namespace_set_peer(peer_ns, NULL, vhca_id); } return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 91dcb0dcad10..aab7059bf6e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -140,7 +140,7 @@ static void mlx5_cmd_stub_modify_header_dealloc(struct mlx5_flow_root_namespace static int mlx5_cmd_stub_set_peer(struct mlx5_flow_root_namespace *ns, struct mlx5_flow_root_namespace *peer_ns, - u8 peer_idx) + u16 peer_vhca_id) { return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h index b6b9a5a20591..7790ae5531e1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h @@ -94,7 +94,7 @@ struct mlx5_flow_cmds { int (*set_peer)(struct mlx5_flow_root_namespace *ns, struct mlx5_flow_root_namespace *peer_ns, - u8 peer_idx); + u16 peer_vhca_id); int (*create_ns)(struct mlx5_flow_root_namespace *ns); int (*destroy_ns)(struct mlx5_flow_root_namespace *ns); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 4ef04aa28771..b4eb27e7f28b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -3621,7 +3621,7 @@ void mlx5_destroy_match_definer(struct mlx5_core_dev *dev, int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, struct mlx5_flow_root_namespace *peer_ns, - u8 peer_idx) + u16 peer_vhca_id) { if (peer_ns && ns->mode != peer_ns->mode) { mlx5_core_err(ns->dev, @@ -3629,7 +3629,7 @@ int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, return -EINVAL; } - return ns->cmds->set_peer(ns, peer_ns, peer_idx); + return ns->cmds->set_peer(ns, peer_ns, peer_vhca_id); } /* This function should be called only at init stage of the namespace. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 03e64c4c245d..4aed1768b85f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -303,7 +303,7 @@ const struct mlx5_flow_cmds *mlx5_fs_cmd_get_fw_cmds(void); int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, struct mlx5_flow_root_namespace *peer_ns, - u8 peer_idx); + u16 peer_vhca_id); int mlx5_flow_namespace_set_mode(struct mlx5_flow_namespace *ns, enum mlx5_flow_steering_mode mode); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c index e739ec6cdf90..54bb0866ed72 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c @@ -2079,7 +2079,7 @@ mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn, peer_vport = vhca_id_valid && mlx5_core_is_pf(dmn->mdev) && (vhca_id != dmn->info.caps.gvmi); - vport_dmn = peer_vport ? dmn->peer_dmn[vhca_id] : dmn; + vport_dmn = peer_vport ? xa_load(&dmn->peer_dmn_xa, vhca_id) : dmn; if (!vport_dmn) { mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n"); return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c index 75dc85dc24ef..3d74109f8230 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c @@ -475,6 +475,7 @@ mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) mutex_init(&dmn->info.rx.mutex); mutex_init(&dmn->info.tx.mutex); xa_init(&dmn->definers_xa); + xa_init(&dmn->peer_dmn_xa); if (dr_domain_caps_init(mdev, dmn)) { mlx5dr_err(dmn, "Failed init domain, no caps\n"); @@ -507,6 +508,7 @@ mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) uninit_caps: dr_domain_caps_uninit(dmn); def_xa_destroy: + xa_destroy(&dmn->peer_dmn_xa); xa_destroy(&dmn->definers_xa); kfree(dmn); return NULL; @@ -547,6 +549,7 @@ int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn) dr_domain_uninit_csum_recalc_fts(dmn); dr_domain_uninit_resources(dmn); dr_domain_caps_uninit(dmn); + xa_destroy(&dmn->peer_dmn_xa); xa_destroy(&dmn->definers_xa); mutex_destroy(&dmn->info.tx.mutex); mutex_destroy(&dmn->info.rx.mutex); @@ -556,17 +559,21 @@ int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn) void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, struct mlx5dr_domain *peer_dmn, - u8 peer_idx) + u16 peer_vhca_id) { + struct mlx5dr_domain *peer; + mlx5dr_domain_lock(dmn); - if (dmn->peer_dmn[peer_idx]) - refcount_dec(&dmn->peer_dmn[peer_idx]->refcount); + peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); + if (peer) + refcount_dec(&peer->refcount); - dmn->peer_dmn[peer_idx] = peer_dmn; + WARN_ON(xa_err(xa_store(&dmn->peer_dmn_xa, peer_vhca_id, peer_dmn, GFP_KERNEL))); - if (dmn->peer_dmn[peer_idx]) - refcount_inc(&dmn->peer_dmn[peer_idx]->refcount); + peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); + if (peer) + refcount_inc(&peer->refcount); mlx5dr_domain_unlock(dmn); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c index 69d7a8f3c402..f708b029425a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c @@ -1652,17 +1652,18 @@ dr_ste_v0_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, struct mlx5dr_domain *dmn = sb->dmn; struct mlx5dr_domain *vport_dmn; u8 *bit_mask = sb->bit_mask; + struct mlx5dr_domain *peer; bool source_gvmi_set; DR_STE_SET_TAG(src_gvmi_qp, tag, source_qp, misc, source_sqn); if (sb->vhca_id_valid) { + peer = xa_load(&dmn->peer_dmn_xa, id); /* Find port GVMI based on the eswitch_owner_vhca_id */ if (id == dmn->info.caps.gvmi) vport_dmn = dmn; - else if (id < MLX5_MAX_PORTS && dmn->peer_dmn[id] && - (id == dmn->peer_dmn[id]->info.caps.gvmi)) - vport_dmn = dmn->peer_dmn[id]; + else if (peer && (id == peer->info.caps.gvmi)) + vport_dmn = peer; else return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c index f4ef0b22b991..dd856cde188d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c @@ -1984,16 +1984,17 @@ static int dr_ste_v1_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, struct mlx5dr_domain *dmn = sb->dmn; struct mlx5dr_domain *vport_dmn; u8 *bit_mask = sb->bit_mask; + struct mlx5dr_domain *peer; DR_STE_SET_TAG(src_gvmi_qp_v1, tag, source_qp, misc, source_sqn); if (sb->vhca_id_valid) { + peer = xa_load(&dmn->peer_dmn_xa, id); /* Find port GVMI based on the eswitch_owner_vhca_id */ if (id == dmn->info.caps.gvmi) vport_dmn = dmn; - else if (id < MLX5_MAX_PORTS && dmn->peer_dmn[id] && - (id == dmn->peer_dmn[id]->info.caps.gvmi)) - vport_dmn = dmn->peer_dmn[id]; + else if (peer && (id == peer->info.caps.gvmi)) + vport_dmn = peer; else return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h index 1622dbbe6b97..6c59de3e28f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -935,7 +935,6 @@ struct mlx5dr_domain_info { }; struct mlx5dr_domain { - struct mlx5dr_domain *peer_dmn[MLX5_MAX_PORTS]; struct mlx5_core_dev *mdev; u32 pdn; struct mlx5_uars_page *uar; @@ -956,6 +955,7 @@ struct mlx5dr_domain { struct list_head dbg_tbl_list; struct mlx5dr_dbg_dump_info dump_info; struct xarray definers_xa; + struct xarray peer_dmn_xa; /* memory management statistics */ u32 num_buddies[DR_ICM_TYPE_MAX]; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c index 6aac5f006bf8..feb307fb3440 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c @@ -781,14 +781,14 @@ restore_fte: static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, struct mlx5_flow_root_namespace *peer_ns, - u8 peer_idx) + u16 peer_vhca_id) { struct mlx5dr_domain *peer_domain = NULL; if (peer_ns) peer_domain = peer_ns->fs_dr_domain.dr_domain; mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, - peer_domain, peer_idx); + peer_domain, peer_vhca_id); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h index 24cbb33ecd6c..89fced86936f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h @@ -49,7 +49,7 @@ int mlx5dr_domain_sync(struct mlx5dr_domain *domain, u32 flags); void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, struct mlx5dr_domain *peer_dmn, - u8 peer_idx); + u16 peer_vhca_id); struct mlx5dr_table * mlx5dr_table_create(struct mlx5dr_domain *domain, u32 level, u32 flags, -- cgit v1.2.3 From 53d737dfd3d7b023fa9fa445ea3f3db0ac9da402 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Sun, 25 Jun 2023 11:07:38 +0300 Subject: net/mlx5: Unregister devlink params in case interface is down Currently, in case an interface is down, mlx5 driver doesn't unregister its devlink params, which leads to this WARN[1]. Fix it by unregistering devlink params in that case as well. [1] [ 295.244769 ] WARNING: CPU: 15 PID: 1 at net/core/devlink.c:9042 devlink_free+0x174/0x1fc [ 295.488379 ] CPU: 15 PID: 1 Comm: shutdown Tainted: G S OE 5.15.0-1017.19.3.g0677e61-bluefield #g0677e61 [ 295.509330 ] Hardware name: https://www.mellanox.com BlueField SoC/BlueField SoC, BIOS 4.2.0.12761 Jun 6 2023 [ 295.543096 ] pc : devlink_free+0x174/0x1fc [ 295.551104 ] lr : mlx5_devlink_free+0x18/0x2c [mlx5_core] [ 295.561816 ] sp : ffff80000809b850 [ 295.711155 ] Call trace: [ 295.716030 ] devlink_free+0x174/0x1fc [ 295.723346 ] mlx5_devlink_free+0x18/0x2c [mlx5_core] [ 295.733351 ] mlx5_sf_dev_remove+0x98/0xb0 [mlx5_core] [ 295.743534 ] auxiliary_bus_remove+0x2c/0x50 [ 295.751893 ] __device_release_driver+0x19c/0x280 [ 295.761120 ] device_release_driver+0x34/0x50 [ 295.769649 ] bus_remove_device+0xdc/0x170 [ 295.777656 ] device_del+0x17c/0x3a4 [ 295.784620 ] mlx5_sf_dev_remove+0x28/0xf0 [mlx5_core] [ 295.794800 ] mlx5_sf_dev_table_destroy+0x98/0x110 [mlx5_core] [ 295.806375 ] mlx5_unload+0x34/0xd0 [mlx5_core] [ 295.815339 ] mlx5_unload_one+0x70/0xe4 [mlx5_core] [ 295.824998 ] shutdown+0xb0/0xd8 [mlx5_core] [ 295.833439 ] pci_device_shutdown+0x3c/0xa0 [ 295.841651 ] device_shutdown+0x170/0x340 [ 295.849486 ] __do_sys_reboot+0x1f4/0x2a0 [ 295.857322 ] __arm64_sys_reboot+0x2c/0x40 [ 295.865329 ] invoke_syscall+0x78/0x100 [ 295.872817 ] el0_svc_common.constprop.0+0x54/0x184 [ 295.882392 ] do_el0_svc+0x30/0xac [ 295.889008 ] el0_svc+0x48/0x160 [ 295.895278 ] el0t_64_sync_handler+0xa4/0x130 [ 295.903807 ] el0t_64_sync+0x1a4/0x1a8 [ 295.911120 ] ---[ end trace 4f1d2381d00d9dce ]--- Fixes: fe578cbb2f05 ("net/mlx5: Move devlink registration before mlx5_load") Signed-off-by: Shay Drory Reviewed-by: Maher Sanalla Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 88dbea6631d5..f42abc2ea73c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1506,6 +1506,7 @@ void mlx5_uninit_one(struct mlx5_core_dev *dev) if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) { mlx5_core_warn(dev, "%s: interface is down, NOP\n", __func__); + mlx5_devlink_params_unregister(priv_to_devlink(dev)); mlx5_cleanup_once(dev); goto out; } -- cgit v1.2.3 From a8f014ec6a214c94ed6a9ff5ba8904a5cadd42a6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 20 Jul 2023 08:15:06 -0700 Subject: vboxsf: Use flexible arrays for trailing string member The declaration of struct shfl_string used trailing fake flexible arrays for the string member. This was tripping FORTIFY_SOURCE since commit df8fc4e934c1 ("kbuild: Enable -fstrict-flex-arrays=3"). Replace the utf8 and utf16 members with actual flexible arrays, drop the unused ucs2 member, and retriain a 2 byte padding to keep the structure size the same. Reported-by: Larry Finger Closes: https://lore.kernel.org/lkml/ab3a70e9-60ed-0f13-e3d4-8866eaccc8c1@lwfinger.net/ Tested-by: Larry Finger Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230720151458.never.673-kees@kernel.org Signed-off-by: Kees Cook --- fs/vboxsf/shfl_hostintf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/vboxsf/shfl_hostintf.h b/fs/vboxsf/shfl_hostintf.h index aca829062c12..069a019c9247 100644 --- a/fs/vboxsf/shfl_hostintf.h +++ b/fs/vboxsf/shfl_hostintf.h @@ -68,9 +68,9 @@ struct shfl_string { /** UTF-8 or UTF-16 string. Nul terminated. */ union { - u8 utf8[2]; - u16 utf16[1]; - u16 ucs2[1]; /* misnomer, use utf16. */ + u8 legacy_padding[2]; + DECLARE_FLEX_ARRAY(u8, utf8); + DECLARE_FLEX_ARRAY(u16, utf16); } string; }; VMMDEV_ASSERT_SIZE(shfl_string, 6); -- cgit v1.2.3 From 2dedcf414bb01b8d966eb445db1d181d92304fb2 Mon Sep 17 00:00:00 2001 From: Guchun Chen Date: Mon, 24 Jul 2023 10:42:29 +0800 Subject: drm/ttm: check null pointer before accessing when swapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a check to avoid null pointer dereference as below: [ 90.002283] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI [ 90.002292] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] [ 90.002346] ? exc_general_protection+0x159/0x240 [ 90.002352] ? asm_exc_general_protection+0x26/0x30 [ 90.002357] ? ttm_bo_evict_swapout_allowable+0x322/0x5e0 [ttm] [ 90.002365] ? ttm_bo_evict_swapout_allowable+0x42e/0x5e0 [ttm] [ 90.002373] ttm_bo_swapout+0x134/0x7f0 [ttm] [ 90.002383] ? __pfx_ttm_bo_swapout+0x10/0x10 [ttm] [ 90.002391] ? lock_acquire+0x44d/0x4f0 [ 90.002398] ? ttm_device_swapout+0xa5/0x260 [ttm] [ 90.002412] ? lock_acquired+0x355/0xa00 [ 90.002416] ? do_raw_spin_trylock+0xb6/0x190 [ 90.002421] ? __pfx_lock_acquired+0x10/0x10 [ 90.002426] ? ttm_global_swapout+0x25/0x210 [ttm] [ 90.002442] ttm_device_swapout+0x198/0x260 [ttm] [ 90.002456] ? __pfx_ttm_device_swapout+0x10/0x10 [ttm] [ 90.002472] ttm_global_swapout+0x75/0x210 [ttm] [ 90.002486] ttm_tt_populate+0x187/0x3f0 [ttm] [ 90.002501] ttm_bo_handle_move_mem+0x437/0x590 [ttm] [ 90.002517] ttm_bo_validate+0x275/0x430 [ttm] [ 90.002530] ? __pfx_ttm_bo_validate+0x10/0x10 [ttm] [ 90.002544] ? kasan_save_stack+0x33/0x60 [ 90.002550] ? kasan_set_track+0x25/0x30 [ 90.002554] ? __kasan_kmalloc+0x8f/0xa0 [ 90.002558] ? amdgpu_gtt_mgr_new+0x81/0x420 [amdgpu] [ 90.003023] ? ttm_resource_alloc+0xf6/0x220 [ttm] [ 90.003038] amdgpu_bo_pin_restricted+0x2dd/0x8b0 [amdgpu] [ 90.003210] ? __x64_sys_ioctl+0x131/0x1a0 [ 90.003210] ? do_syscall_64+0x60/0x90 Fixes: a2848d08742c ("drm/ttm: never consider pinned BOs for eviction&swap") Tested-by: Mikhail Gavrilov Signed-off-by: Guchun Chen Reviewed-by: Alex Deucher Reviewed-by: Christian König Cc: stable@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20230724024229.1118444-1-guchun.chen@amd.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 7139a522b2f3..54e3083076b7 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -519,7 +519,8 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, if (bo->pin_count) { *locked = false; - *busy = false; + if (busy) + *busy = false; return false; } -- cgit v1.2.3 From fb3bd914b3ec28f5fb697ac55c4846ac2d542855 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 28 Jun 2023 11:02:39 +0200 Subject: x86/srso: Add a Speculative RAS Overflow mitigation Add a mitigation for the speculative return address stack overflow vulnerability found on AMD processors. The mitigation works by ensuring all RET instructions speculate to a controlled location, similar to how speculation is controlled in the retpoline sequence. To accomplish this, the __x86_return_thunk forces the CPU to mispredict every function return using a 'safe return' sequence. To ensure the safety of this mitigation, the kernel must ensure that the safe return sequence is itself free from attacker interference. In Zen3 and Zen4, this is accomplished by creating a BTB alias between the untraining function srso_untrain_ret_alias() and the safe return function srso_safe_ret_alias() which results in evicting a potentially poisoned BTB entry and using that safe one for all function returns. In older Zen1 and Zen2, this is accomplished using a reinterpretation technique similar to Retbleed one: srso_untrain_ret() and srso_safe_ret(). Signed-off-by: Borislav Petkov (AMD) --- Documentation/admin-guide/hw-vuln/index.rst | 1 + Documentation/admin-guide/hw-vuln/srso.rst | 133 ++++++++++++++++++++++++ Documentation/admin-guide/kernel-parameters.txt | 11 ++ arch/x86/Kconfig | 7 ++ arch/x86/include/asm/cpufeatures.h | 5 + arch/x86/include/asm/nospec-branch.h | 15 ++- arch/x86/include/asm/processor.h | 2 + arch/x86/kernel/alternative.c | 4 +- arch/x86/kernel/cpu/amd.c | 14 +++ arch/x86/kernel/cpu/bugs.c | 106 +++++++++++++++++++ arch/x86/kernel/cpu/common.c | 8 +- arch/x86/kernel/vmlinux.lds.S | 29 +++++- arch/x86/lib/retpoline.S | 82 ++++++++++++++- drivers/base/cpu.c | 8 ++ include/linux/cpu.h | 2 + tools/objtool/arch/x86/decode.c | 5 +- 16 files changed, 422 insertions(+), 10 deletions(-) create mode 100644 Documentation/admin-guide/hw-vuln/srso.rst diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst index e0614760a99e..ff4d3fa2a75c 100644 --- a/Documentation/admin-guide/hw-vuln/index.rst +++ b/Documentation/admin-guide/hw-vuln/index.rst @@ -19,3 +19,4 @@ are configurable at compile, boot or run time. l1d_flush.rst processor_mmio_stale_data.rst cross-thread-rsb.rst + srso diff --git a/Documentation/admin-guide/hw-vuln/srso.rst b/Documentation/admin-guide/hw-vuln/srso.rst new file mode 100644 index 000000000000..32eb5e6db272 --- /dev/null +++ b/Documentation/admin-guide/hw-vuln/srso.rst @@ -0,0 +1,133 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Speculative Return Stack Overflow (SRSO) +======================================== + +This is a mitigation for the speculative return stack overflow (SRSO) +vulnerability found on AMD processors. The mechanism is by now the well +known scenario of poisoning CPU functional units - the Branch Target +Buffer (BTB) and Return Address Predictor (RAP) in this case - and then +tricking the elevated privilege domain (the kernel) into leaking +sensitive data. + +AMD CPUs predict RET instructions using a Return Address Predictor (aka +Return Address Stack/Return Stack Buffer). In some cases, a non-architectural +CALL instruction (i.e., an instruction predicted to be a CALL but is +not actually a CALL) can create an entry in the RAP which may be used +to predict the target of a subsequent RET instruction. + +The specific circumstances that lead to this varies by microarchitecture +but the concern is that an attacker can mis-train the CPU BTB to predict +non-architectural CALL instructions in kernel space and use this to +control the speculative target of a subsequent kernel RET, potentially +leading to information disclosure via a speculative side-channel. + +The issue is tracked under CVE-2023-20569. + +Affected processors +------------------- + +AMD Zen, generations 1-4. That is, all families 0x17 and 0x19. Older +processors have not been investigated. + +System information and options +------------------------------ + +First of all, it is required that the latest microcode be loaded for +mitigations to be effective. + +The sysfs file showing SRSO mitigation status is: + + /sys/devices/system/cpu/vulnerabilities/spec_rstack_overflow + +The possible values in this file are: + + - 'Not affected' The processor is not vulnerable + + - 'Vulnerable: no microcode' The processor is vulnerable, no + microcode extending IBPB functionality + to address the vulnerability has been + applied. + + - 'Mitigation: microcode' Extended IBPB functionality microcode + patch has been applied. It does not + address User->Kernel and Guest->Host + transitions protection but it does + address User->User and VM->VM attack + vectors. + + (spec_rstack_overflow=microcode) + + - 'Mitigation: safe RET' Software-only mitigation. It complements + the extended IBPB microcode patch + functionality by addressing User->Kernel + and Guest->Host transitions protection. + + Selected by default or by + spec_rstack_overflow=safe-ret + + - 'Mitigation: IBPB' Similar protection as "safe RET" above + but employs an IBPB barrier on privilege + domain crossings (User->Kernel, + Guest->Host). + + (spec_rstack_overflow=ibpb) + + - 'Mitigation: IBPB on VMEXIT' Mitigation addressing the cloud provider + scenario - the Guest->Host transitions + only. + + (spec_rstack_overflow=ibpb-vmexit) + +In order to exploit vulnerability, an attacker needs to: + + - gain local access on the machine + + - break kASLR + + - find gadgets in the running kernel in order to use them in the exploit + + - potentially create and pin an additional workload on the sibling + thread, depending on the microarchitecture (not necessary on fam 0x19) + + - run the exploit + +Considering the performance implications of each mitigation type, the +default one is 'Mitigation: safe RET' which should take care of most +attack vectors, including the local User->Kernel one. + +As always, the user is advised to keep her/his system up-to-date by +applying software updates regularly. + +The default setting will be reevaluated when needed and especially when +new attack vectors appear. + +As one can surmise, 'Mitigation: safe RET' does come at the cost of some +performance depending on the workload. If one trusts her/his userspace +and does not want to suffer the performance impact, one can always +disable the mitigation with spec_rstack_overflow=off. + +Similarly, 'Mitigation: IBPB' is another full mitigation type employing +an indrect branch prediction barrier after having applied the required +microcode patch for one's system. This mitigation comes also at +a performance cost. + +Mitigation: safe RET +-------------------- + +The mitigation works by ensuring all RET instructions speculate to +a controlled location, similar to how speculation is controlled in the +retpoline sequence. To accomplish this, the __x86_return_thunk forces +the CPU to mispredict every function return using a 'safe return' +sequence. + +To ensure the safety of this mitigation, the kernel must ensure that the +safe return sequence is itself free from attacker interference. In Zen3 +and Zen4, this is accomplished by creating a BTB alias between the +untraining function srso_untrain_ret_alias() and the safe return +function srso_safe_ret_alias() which results in evicting a potentially +poisoned BTB entry and using that safe one for all function returns. + +In older Zen1 and Zen2, this is accomplished using a reinterpretation +technique similar to Retbleed one: srso_untrain_ret() and +srso_safe_ret(). diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a1457995fd41..f5ec3dade58e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5875,6 +5875,17 @@ Not specifying this option is equivalent to spectre_v2_user=auto. + spec_rstack_overflow= + [X86] Control RAS overflow mitigation on AMD Zen CPUs + + off - Disable mitigation + microcode - Enable microcode mitigation only + safe-ret - Enable sw-only safe RET mitigation (default) + ibpb - Enable mitigation by issuing IBPB on + kernel entry + ibpb-vmexit - Issue IBPB only on VMEXIT + (cloud-specific mitigation) + spec_store_bypass_disable= [HW] Control Speculative Store Bypass (SSB) Disable mitigation (Speculative Store Bypass vulnerability) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7422db409770..d29f1e28a936 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2593,6 +2593,13 @@ config CPU_IBRS_ENTRY This mitigates both spectre_v2 and retbleed at great cost to performance. +config CPU_SRSO + bool "Mitigate speculative RAS overflow on AMD" + depends on CPU_SUP_AMD && X86_64 && RETHUNK + default y + help + Enable the SRSO mitigation needed on AMD Zen1-4 machines. + config SLS bool "Mitigate Straight-Line-Speculation" depends on CC_HAS_SLS && X86_64 diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 1f6d904c6481..bc1b4d68e616 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -309,6 +309,9 @@ #define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */ #define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */ +#define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ +#define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ + /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */ @@ -484,4 +487,6 @@ #define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */ #define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */ +/* BUG word 2 */ +#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 1a65cf4acb2b..43fe1c747085 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -211,7 +211,8 @@ * eventually turn into it's own annotation. */ .macro VALIDATE_UNRET_END -#if defined(CONFIG_NOINSTR_VALIDATION) && defined(CONFIG_CPU_UNRET_ENTRY) +#if defined(CONFIG_NOINSTR_VALIDATION) && \ + (defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO)) ANNOTATE_RETPOLINE_SAFE nop #endif @@ -296,6 +297,11 @@ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ __stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH #endif + +#ifdef CONFIG_CPU_SRSO + ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \ + "call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS +#endif .endm .macro UNTRAIN_RET_FROM_CALL @@ -307,6 +313,11 @@ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ __stringify(RESET_CALL_DEPTH_FROM_CALL), X86_FEATURE_CALL_DEPTH #endif + +#ifdef CONFIG_CPU_SRSO + ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \ + "call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS +#endif .endm @@ -332,6 +343,8 @@ extern retpoline_thunk_t __x86_indirect_jump_thunk_array[]; extern void __x86_return_thunk(void); extern void zen_untrain_ret(void); +extern void srso_untrain_ret(void); +extern void srso_untrain_ret_alias(void); extern void entry_ibpb(void); #ifdef CONFIG_CALL_THUNKS diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index d46300e94f85..7c67db7c9f53 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -682,9 +682,11 @@ extern u16 get_llc_id(unsigned int cpu); #ifdef CONFIG_CPU_SUP_AMD extern u32 amd_get_nodes_per_socket(void); extern u32 amd_get_highest_perf(void); +extern bool cpu_has_ibpb_brtype_microcode(void); #else static inline u32 amd_get_nodes_per_socket(void) { return 0; } static inline u32 amd_get_highest_perf(void) { return 0; } +static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; } #endif extern unsigned long arch_align_stack(unsigned long sp); diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 2dcf3a06af09..920a8ca7a8f8 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -707,7 +707,9 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes) int i = 0; /* Patch the custom return thunks... */ - if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { + if (cpu_feature_enabled(X86_FEATURE_RETHUNK) || + cpu_feature_enabled(X86_FEATURE_SRSO) || + cpu_feature_enabled(X86_FEATURE_SRSO_ALIAS)) { i = JMP32_INSN_SIZE; __text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i); } else { diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 571abf808ea3..169cb255c483 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1235,3 +1235,17 @@ u32 amd_get_highest_perf(void) return 255; } EXPORT_SYMBOL_GPL(amd_get_highest_perf); + +bool cpu_has_ibpb_brtype_microcode(void) +{ + u8 fam = boot_cpu_data.x86; + + if (fam == 0x17) { + /* Zen1/2 IBPB flushes branch type predictions too. */ + return boot_cpu_has(X86_FEATURE_AMD_IBPB); + } else if (fam == 0x19) { + return false; + } + + return false; +} diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 9e2a91830f72..31cef61da03a 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -47,6 +47,7 @@ static void __init taa_select_mitigation(void); static void __init mmio_select_mitigation(void); static void __init srbds_select_mitigation(void); static void __init l1d_flush_select_mitigation(void); +static void __init srso_select_mitigation(void); /* The base value of the SPEC_CTRL MSR without task-specific bits set */ u64 x86_spec_ctrl_base; @@ -160,6 +161,7 @@ void __init cpu_select_mitigations(void) md_clear_select_mitigation(); srbds_select_mitigation(); l1d_flush_select_mitigation(); + srso_select_mitigation(); } /* @@ -2185,6 +2187,95 @@ static int __init l1tf_cmdline(char *str) } early_param("l1tf", l1tf_cmdline); +#undef pr_fmt +#define pr_fmt(fmt) "Speculative Return Stack Overflow: " fmt + +enum srso_mitigation { + SRSO_MITIGATION_NONE, + SRSO_MITIGATION_MICROCODE, + SRSO_MITIGATION_SAFE_RET, +}; + +enum srso_mitigation_cmd { + SRSO_CMD_OFF, + SRSO_CMD_MICROCODE, + SRSO_CMD_SAFE_RET, +}; + +static const char * const srso_strings[] = { + [SRSO_MITIGATION_NONE] = "Vulnerable", + [SRSO_MITIGATION_MICROCODE] = "Mitigation: microcode", + [SRSO_MITIGATION_SAFE_RET] = "Mitigation: safe RET", +}; + +static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE; +static enum srso_mitigation_cmd srso_cmd __ro_after_init = SRSO_CMD_SAFE_RET; + +static int __init srso_parse_cmdline(char *str) +{ + if (!str) + return -EINVAL; + + if (!strcmp(str, "off")) + srso_cmd = SRSO_CMD_OFF; + else if (!strcmp(str, "microcode")) + srso_cmd = SRSO_CMD_MICROCODE; + else if (!strcmp(str, "safe-ret")) + srso_cmd = SRSO_CMD_SAFE_RET; + else + pr_err("Ignoring unknown SRSO option (%s).", str); + + return 0; +} +early_param("spec_rstack_overflow", srso_parse_cmdline); + +#define SRSO_NOTICE "WARNING: See https://kernel.org/doc/html/latest/admin-guide/hw-vuln/srso.html for mitigation options." + +static void __init srso_select_mitigation(void) +{ + bool has_microcode; + + if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off()) + return; + + has_microcode = cpu_has_ibpb_brtype_microcode(); + if (!has_microcode) { + pr_warn("IBPB-extending microcode not applied!\n"); + pr_warn(SRSO_NOTICE); + } + + switch (srso_cmd) { + case SRSO_CMD_OFF: + return; + + case SRSO_CMD_MICROCODE: + if (has_microcode) { + srso_mitigation = SRSO_MITIGATION_MICROCODE; + pr_warn(SRSO_NOTICE); + } + break; + + case SRSO_CMD_SAFE_RET: + if (IS_ENABLED(CONFIG_CPU_SRSO)) { + if (boot_cpu_data.x86 == 0x19) + setup_force_cpu_cap(X86_FEATURE_SRSO_ALIAS); + else + setup_force_cpu_cap(X86_FEATURE_SRSO); + srso_mitigation = SRSO_MITIGATION_SAFE_RET; + } else { + pr_err("WARNING: kernel not compiled with CPU_SRSO.\n"); + return; + } + break; + + default: + break; + + } + + pr_info("%s%s\n", srso_strings[srso_mitigation], (has_microcode ? "" : ", no microcode")); +} + #undef pr_fmt #define pr_fmt(fmt) fmt @@ -2382,6 +2473,13 @@ static ssize_t retbleed_show_state(char *buf) return sysfs_emit(buf, "%s\n", retbleed_strings[retbleed_mitigation]); } +static ssize_t srso_show_state(char *buf) +{ + return sysfs_emit(buf, "%s%s\n", + srso_strings[srso_mitigation], + (cpu_has_ibpb_brtype_microcode() ? "" : ", no microcode")); +} + static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, char *buf, unsigned int bug) { @@ -2431,6 +2529,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr case X86_BUG_RETBLEED: return retbleed_show_state(buf); + case X86_BUG_SRSO: + return srso_show_state(buf); + default: break; } @@ -2495,4 +2596,9 @@ ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, cha { return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED); } + +ssize_t cpu_show_spec_rstack_overflow(struct device *dev, struct device_attribute *attr, char *buf) +{ + return cpu_show_common(dev, attr, buf, X86_BUG_SRSO); +} #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 52683fddafaf..d4d823eae0fc 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1250,6 +1250,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { #define RETBLEED BIT(3) /* CPU is affected by SMT (cross-thread) return predictions */ #define SMT_RSB BIT(4) +/* CPU is affected by SRSO */ +#define SRSO BIT(5) static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS), @@ -1281,8 +1283,9 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_AMD(0x15, RETBLEED), VULNBL_AMD(0x16, RETBLEED), - VULNBL_AMD(0x17, RETBLEED | SMT_RSB), + VULNBL_AMD(0x17, RETBLEED | SMT_RSB | SRSO), VULNBL_HYGON(0x18, RETBLEED | SMT_RSB), + VULNBL_AMD(0x19, SRSO), {} }; @@ -1406,6 +1409,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) if (cpu_matches(cpu_vuln_blacklist, SMT_RSB)) setup_force_cpu_bug(X86_BUG_SMT_RSB); + if (cpu_matches(cpu_vuln_blacklist, SRSO)) + setup_force_cpu_bug(X86_BUG_SRSO); + if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) return; diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 03c885d3640f..e76813230192 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -134,13 +134,27 @@ SECTIONS SOFTIRQENTRY_TEXT #ifdef CONFIG_RETPOLINE __indirect_thunk_start = .; - *(.text.__x86.*) + *(.text.__x86.indirect_thunk) + *(.text.__x86.return_thunk) __indirect_thunk_end = .; #endif STATIC_CALL_TEXT ALIGN_ENTRY_TEXT_BEGIN +#ifdef CONFIG_CPU_SRSO + *(.text.__x86.rethunk_untrain) +#endif + ENTRY_TEXT + +#ifdef CONFIG_CPU_SRSO + /* + * See the comment above srso_untrain_ret_alias()'s + * definition. + */ + . = srso_untrain_ret_alias | (1 << 2) | (1 << 8) | (1 << 14) | (1 << 20); + *(.text.__x86.rethunk_safe) +#endif ALIGN_ENTRY_TEXT_END *(.gnu.warning) @@ -509,7 +523,18 @@ INIT_PER_CPU(irq_stack_backing_store); #endif #ifdef CONFIG_RETHUNK -. = ASSERT((__x86_return_thunk & 0x3f) == 0, "__x86_return_thunk not cacheline-aligned"); +. = ASSERT((__ret & 0x3f) == 0, "__ret not cacheline-aligned"); +. = ASSERT((srso_safe_ret & 0x3f) == 0, "srso_safe_ret not cacheline-aligned"); +#endif + +#ifdef CONFIG_CPU_SRSO +/* + * GNU ld cannot do XOR so do: (A | B) - (A & B) in order to compute the XOR + * of the two function addresses: + */ +. = ASSERT(((srso_untrain_ret_alias | srso_safe_ret_alias) - + (srso_untrain_ret_alias & srso_safe_ret_alias)) == ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 20)), + "SRSO function pair won't alias"); #endif #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index 3fd066d42ec0..845cfb0d748f 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -11,6 +11,7 @@ #include #include #include +#include .section .text.__x86.indirect_thunk @@ -131,6 +132,45 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) */ #ifdef CONFIG_RETHUNK +/* + * srso_untrain_ret_alias() and srso_safe_ret_alias() are placed at + * special addresses: + * + * - srso_untrain_ret_alias() is 2M aligned + * - srso_safe_ret_alias() is also in the same 2M page but bits 2, 8, 14 + * and 20 in its virtual address are set (while those bits in the + * srso_untrain_ret_alias() function are cleared). + * + * This guarantees that those two addresses will alias in the branch + * target buffer of Zen3/4 generations, leading to any potential + * poisoned entries at that BTB slot to get evicted. + * + * As a result, srso_safe_ret_alias() becomes a safe return. + */ +#ifdef CONFIG_CPU_SRSO + .section .text.__x86.rethunk_untrain + +SYM_START(srso_untrain_ret_alias, SYM_L_GLOBAL, SYM_A_NONE) + ASM_NOP2 + lfence + jmp __x86_return_thunk +SYM_FUNC_END(srso_untrain_ret_alias) +__EXPORT_THUNK(srso_untrain_ret_alias) + + .section .text.__x86.rethunk_safe +#endif + +/* Needs a definition for the __x86_return_thunk alternative below. */ +SYM_START(srso_safe_ret_alias, SYM_L_GLOBAL, SYM_A_NONE) +#ifdef CONFIG_CPU_SRSO + add $8, %_ASM_SP + UNWIND_HINT_FUNC +#endif + ANNOTATE_UNRET_SAFE + ret + int3 +SYM_FUNC_END(srso_safe_ret_alias) + .section .text.__x86.return_thunk /* @@ -143,7 +183,7 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) * from re-poisioning the BTB prediction. */ .align 64 - .skip 64 - (__x86_return_thunk - zen_untrain_ret), 0xcc + .skip 64 - (__ret - zen_untrain_ret), 0xcc SYM_START(zen_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) ANNOTATE_NOENDBR /* @@ -175,10 +215,10 @@ SYM_START(zen_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) * evicted, __x86_return_thunk will suffer Straight Line Speculation * which will be contained safely by the INT3. */ -SYM_INNER_LABEL(__x86_return_thunk, SYM_L_GLOBAL) +SYM_INNER_LABEL(__ret, SYM_L_GLOBAL) ret int3 -SYM_CODE_END(__x86_return_thunk) +SYM_CODE_END(__ret) /* * Ensure the TEST decoding / BTB invalidation is complete. @@ -189,11 +229,45 @@ SYM_CODE_END(__x86_return_thunk) * Jump back and execute the RET in the middle of the TEST instruction. * INT3 is for SLS protection. */ - jmp __x86_return_thunk + jmp __ret int3 SYM_FUNC_END(zen_untrain_ret) __EXPORT_THUNK(zen_untrain_ret) +/* + * SRSO untraining sequence for Zen1/2, similar to zen_untrain_ret() + * above. On kernel entry, srso_untrain_ret() is executed which is a + * + * movabs $0xccccccc308c48348,%rax + * + * and when the return thunk executes the inner label srso_safe_ret() + * later, it is a stack manipulation and a RET which is mispredicted and + * thus a "safe" one to use. + */ + .align 64 + .skip 64 - (srso_safe_ret - srso_untrain_ret), 0xcc +SYM_START(srso_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) + ANNOTATE_NOENDBR + .byte 0x48, 0xb8 + +SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL) + add $8, %_ASM_SP + ret + int3 + int3 + int3 + lfence + call srso_safe_ret + int3 +SYM_CODE_END(srso_safe_ret) +SYM_FUNC_END(srso_untrain_ret) +__EXPORT_THUNK(srso_untrain_ret) + +SYM_FUNC_START(__x86_return_thunk) + ALTERNATIVE_2 "jmp __ret", "call srso_safe_ret", X86_FEATURE_SRSO, \ + "call srso_safe_ret_alias", X86_FEATURE_SRSO_ALIAS + int3 +SYM_CODE_END(__x86_return_thunk) EXPORT_SYMBOL(__x86_return_thunk) #endif /* CONFIG_RETHUNK */ diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c1815b9dae68..f111586d1cce 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -577,6 +577,12 @@ ssize_t __weak cpu_show_retbleed(struct device *dev, return sysfs_emit(buf, "Not affected\n"); } +ssize_t __weak cpu_show_spec_rstack_overflow(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); @@ -588,6 +594,7 @@ static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL); static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL); static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL); static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); +static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, @@ -601,6 +608,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_srbds.attr, &dev_attr_mmio_stale_data.attr, &dev_attr_retbleed.attr, + &dev_attr_spec_rstack_overflow.attr, NULL }; diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 6e6e57ec69e8..23ac87be1ff1 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -70,6 +70,8 @@ extern ssize_t cpu_show_mmio_stale_data(struct device *dev, char *buf); extern ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf); +extern ssize_t cpu_show_spec_rstack_overflow(struct device *dev, + struct device_attribute *attr, char *buf); extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 2e1caabecb18..2d51fa8da9e8 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -824,5 +824,8 @@ bool arch_is_retpoline(struct symbol *sym) bool arch_is_rethunk(struct symbol *sym) { - return !strcmp(sym->name, "__x86_return_thunk"); + return !strcmp(sym->name, "__x86_return_thunk") || + !strcmp(sym->name, "srso_untrain_ret") || + !strcmp(sym->name, "srso_safe_ret") || + !strcmp(sym->name, "__ret"); } -- cgit v1.2.3 From 79113e4060aba744787a81edb9014f2865193854 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Tue, 18 Jul 2023 11:13:40 +0200 Subject: x86/srso: Add IBPB_BRTYPE support Add support for the synthetic CPUID flag which "if this bit is 1, it indicates that MSR 49h (PRED_CMD) bit 0 (IBPB) flushes all branch type predictions from the CPU branch predictor." This flag is there so that this capability in guests can be detected easily (otherwise one would have to track microcode revisions which is impossible for guests). It is also needed only for Zen3 and -4. The other two (Zen1 and -2) always flush branch type predictions by default. Signed-off-by: Borislav Petkov (AMD) --- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/kernel/cpu/bugs.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index bc1b4d68e616..8aebe95d2fad 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -445,6 +445,8 @@ #define X86_FEATURE_AUTOIBRS (20*32+ 8) /* "" Automatic IBRS */ #define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* "" SMM_CTL MSR is not present */ +#define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* "" MSR_PRED_CMD[IBPB] flushes all branch type predictions */ + /* * BUG word(s) */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 31cef61da03a..ff61ef61277a 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2238,10 +2238,20 @@ static void __init srso_select_mitigation(void) if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off()) return; - has_microcode = cpu_has_ibpb_brtype_microcode(); + /* + * The first check is for the kernel running as a guest in order + * for guests to verify whether IBPB is a viable mitigation. + */ + has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE) || cpu_has_ibpb_brtype_microcode(); if (!has_microcode) { pr_warn("IBPB-extending microcode not applied!\n"); pr_warn(SRSO_NOTICE); + } else { + /* + * Enable the synthetic (even if in a real CPUID leaf) + * flag for guests. + */ + setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE); } switch (srso_cmd) { -- cgit v1.2.3 From 1b5277c0ea0b247393a9c426769fde18cff5e2f6 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 29 Jun 2023 17:43:40 +0200 Subject: x86/srso: Add SRSO_NO support Add support for the CPUID flag which denotes that the CPU is not affected by SRSO. Signed-off-by: Borislav Petkov (AMD) --- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/nospec-branch.h | 6 +++--- arch/x86/kernel/cpu/amd.c | 12 ++++++------ arch/x86/kernel/cpu/bugs.c | 24 ++++++++++++++++++++---- arch/x86/kernel/cpu/common.c | 6 ++++-- arch/x86/kvm/cpuid.c | 3 +++ 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 8aebe95d2fad..93070aabbb2f 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -445,7 +445,9 @@ #define X86_FEATURE_AUTOIBRS (20*32+ 8) /* "" Automatic IBRS */ #define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* "" SMM_CTL MSR is not present */ +#define X86_FEATURE_SBPB (20*32+27) /* "" Selective Branch Prediction Barrier */ #define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* "" MSR_PRED_CMD[IBPB] flushes all branch type predictions */ +#define X86_FEATURE_SRSO_NO (20*32+29) /* "" CPU is not affected by SRSO */ /* * BUG word(s) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3aedae61af4f..c81483a3c13d 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -57,6 +57,7 @@ #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ #define PRED_CMD_IBPB BIT(0) /* Indirect Branch Prediction Barrier */ +#define PRED_CMD_SBPB BIT(7) /* Selective Branch Prediction Barrier */ #define MSR_PPIN_CTL 0x0000004e #define MSR_PPIN 0x0000004f diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 43fe1c747085..8346c33760c1 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -492,11 +492,11 @@ void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature) : "memory"); } +extern u64 x86_pred_cmd; + static inline void indirect_branch_prediction_barrier(void) { - u64 val = PRED_CMD_IBPB; - - alternative_msr_write(MSR_IA32_PRED_CMD, val, X86_FEATURE_USE_IBPB); + alternative_msr_write(MSR_IA32_PRED_CMD, x86_pred_cmd, X86_FEATURE_USE_IBPB); } /* The Intel SPEC CTRL MSR base value cache */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 169cb255c483..834f310b2f1a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1240,12 +1240,12 @@ bool cpu_has_ibpb_brtype_microcode(void) { u8 fam = boot_cpu_data.x86; - if (fam == 0x17) { - /* Zen1/2 IBPB flushes branch type predictions too. */ + /* Zen1/2 IBPB flushes branch type predictions too. */ + if (fam == 0x17) return boot_cpu_has(X86_FEATURE_AMD_IBPB); - } else if (fam == 0x19) { + /* Poke the MSR bit on Zen3/4 to check its presence. */ + else if (fam == 0x19) + return !wrmsrl_safe(MSR_IA32_PRED_CMD, PRED_CMD_SBPB); + else return false; - } - - return false; } diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ff61ef61277a..439ecad62317 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -57,6 +57,9 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_base); DEFINE_PER_CPU(u64, x86_spec_ctrl_current); EXPORT_SYMBOL_GPL(x86_spec_ctrl_current); +u64 x86_pred_cmd __ro_after_init = PRED_CMD_IBPB; +EXPORT_SYMBOL_GPL(x86_pred_cmd); + static DEFINE_MUTEX(spec_ctrl_mutex); /* Update SPEC_CTRL MSR and its cached copy unconditionally */ @@ -2236,7 +2239,7 @@ static void __init srso_select_mitigation(void) bool has_microcode; if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off()) - return; + goto pred_cmd; /* * The first check is for the kernel running as a guest in order @@ -2249,9 +2252,18 @@ static void __init srso_select_mitigation(void) } else { /* * Enable the synthetic (even if in a real CPUID leaf) - * flag for guests. + * flags for guests. */ setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE); + setup_force_cpu_cap(X86_FEATURE_SBPB); + + /* + * Zen1/2 with SMT off aren't vulnerable after the right + * IBPB microcode has been applied. + */ + if ((boot_cpu_data.x86 < 0x19) && + (cpu_smt_control == CPU_SMT_DISABLED)) + setup_force_cpu_cap(X86_FEATURE_SRSO_NO); } switch (srso_cmd) { @@ -2274,16 +2286,20 @@ static void __init srso_select_mitigation(void) srso_mitigation = SRSO_MITIGATION_SAFE_RET; } else { pr_err("WARNING: kernel not compiled with CPU_SRSO.\n"); - return; + goto pred_cmd; } break; default: break; - } pr_info("%s%s\n", srso_strings[srso_mitigation], (has_microcode ? "" : ", no microcode")); + +pred_cmd: + if (boot_cpu_has(X86_FEATURE_SRSO_NO) || + srso_cmd == SRSO_CMD_OFF) + x86_pred_cmd = PRED_CMD_SBPB; } #undef pr_fmt diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d4d823eae0fc..5576cdac3b4a 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1409,8 +1409,10 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) if (cpu_matches(cpu_vuln_blacklist, SMT_RSB)) setup_force_cpu_bug(X86_BUG_SMT_RSB); - if (cpu_matches(cpu_vuln_blacklist, SRSO)) - setup_force_cpu_bug(X86_BUG_SRSO); + if (!cpu_has(c, X86_FEATURE_SRSO_NO)) { + if (cpu_matches(cpu_vuln_blacklist, SRSO)) + setup_force_cpu_bug(X86_BUG_SRSO); + } if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) return; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 7f4d13383cf2..d3432687c9e6 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -729,6 +729,9 @@ void kvm_set_cpu_caps(void) F(NULL_SEL_CLR_BASE) | F(AUTOIBRS) | 0 /* PrefetchCtlMsr */ ); + if (cpu_feature_enabled(X86_FEATURE_SRSO_NO)) + kvm_cpu_cap_set(X86_FEATURE_SRSO_NO); + kvm_cpu_cap_init_kvm_defined(CPUID_8000_0022_EAX, F(PERFMON_V2) ); -- cgit v1.2.3 From 233d6f68b98d480a7c42ebe78c38f79d44741ca9 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 6 Jul 2023 15:04:35 +0200 Subject: x86/srso: Add IBPB Add the option to mitigate using IBPB on a kernel entry. Pull in the Retbleed alternative so that the IBPB call from there can be used. Also, if Retbleed mitigation is done using IBPB, the same mitigation can and must be used here. Signed-off-by: Borislav Petkov (AMD) --- arch/x86/include/asm/nospec-branch.h | 2 +- arch/x86/kernel/cpu/bugs.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 8346c33760c1..3faf044569a5 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -290,7 +290,7 @@ */ .macro UNTRAIN_RET #if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ - defined(CONFIG_CALL_DEPTH_TRACKING) + defined(CONFIG_CALL_DEPTH_TRACKING) || defined(CONFIG_CPU_SRSO) VALIDATE_UNRET_END ALTERNATIVE_3 "", \ CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 439ecad62317..f3cc432ed818 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2197,18 +2197,21 @@ enum srso_mitigation { SRSO_MITIGATION_NONE, SRSO_MITIGATION_MICROCODE, SRSO_MITIGATION_SAFE_RET, + SRSO_MITIGATION_IBPB, }; enum srso_mitigation_cmd { SRSO_CMD_OFF, SRSO_CMD_MICROCODE, SRSO_CMD_SAFE_RET, + SRSO_CMD_IBPB, }; static const char * const srso_strings[] = { [SRSO_MITIGATION_NONE] = "Vulnerable", [SRSO_MITIGATION_MICROCODE] = "Mitigation: microcode", [SRSO_MITIGATION_SAFE_RET] = "Mitigation: safe RET", + [SRSO_MITIGATION_IBPB] = "Mitigation: IBPB", }; static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE; @@ -2225,6 +2228,8 @@ static int __init srso_parse_cmdline(char *str) srso_cmd = SRSO_CMD_MICROCODE; else if (!strcmp(str, "safe-ret")) srso_cmd = SRSO_CMD_SAFE_RET; + else if (!strcmp(str, "ibpb")) + srso_cmd = SRSO_CMD_IBPB; else pr_err("Ignoring unknown SRSO option (%s).", str); @@ -2266,6 +2271,14 @@ static void __init srso_select_mitigation(void) setup_force_cpu_cap(X86_FEATURE_SRSO_NO); } + if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB) { + if (has_microcode) { + pr_err("Retbleed IBPB mitigation enabled, using same for SRSO\n"); + srso_mitigation = SRSO_MITIGATION_IBPB; + goto pred_cmd; + } + } + switch (srso_cmd) { case SRSO_CMD_OFF: return; @@ -2290,6 +2303,16 @@ static void __init srso_select_mitigation(void) } break; + case SRSO_CMD_IBPB: + if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) { + if (has_microcode) { + setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB); + srso_mitigation = SRSO_MITIGATION_IBPB; + } + } else { + pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n"); + goto pred_cmd; + } default: break; } -- cgit v1.2.3 From d893832d0e1ef41c72cdae444268c1d64a2be8ad Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Fri, 7 Jul 2023 13:53:41 +0200 Subject: x86/srso: Add IBPB on VMEXIT Add the option to flush IBPB only on VMEXIT in order to protect from malicious guests but one otherwise trusts the software that runs on the hypervisor. Signed-off-by: Borislav Petkov (AMD) --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cpu/bugs.c | 19 +++++++++++++++++++ arch/x86/kvm/svm/svm.c | 4 +++- arch/x86/kvm/svm/vmenter.S | 3 +++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 93070aabbb2f..7600a8a1589f 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -311,6 +311,7 @@ #define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ #define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ +#define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* "" Issue an IBPB only on VMEXIT */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index f3cc432ed818..d4109eb5eb2e 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2198,6 +2198,7 @@ enum srso_mitigation { SRSO_MITIGATION_MICROCODE, SRSO_MITIGATION_SAFE_RET, SRSO_MITIGATION_IBPB, + SRSO_MITIGATION_IBPB_ON_VMEXIT, }; enum srso_mitigation_cmd { @@ -2205,6 +2206,7 @@ enum srso_mitigation_cmd { SRSO_CMD_MICROCODE, SRSO_CMD_SAFE_RET, SRSO_CMD_IBPB, + SRSO_CMD_IBPB_ON_VMEXIT, }; static const char * const srso_strings[] = { @@ -2212,6 +2214,7 @@ static const char * const srso_strings[] = { [SRSO_MITIGATION_MICROCODE] = "Mitigation: microcode", [SRSO_MITIGATION_SAFE_RET] = "Mitigation: safe RET", [SRSO_MITIGATION_IBPB] = "Mitigation: IBPB", + [SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only" }; static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE; @@ -2230,6 +2233,8 @@ static int __init srso_parse_cmdline(char *str) srso_cmd = SRSO_CMD_SAFE_RET; else if (!strcmp(str, "ibpb")) srso_cmd = SRSO_CMD_IBPB; + else if (!strcmp(str, "ibpb-vmexit")) + srso_cmd = SRSO_CMD_IBPB_ON_VMEXIT; else pr_err("Ignoring unknown SRSO option (%s).", str); @@ -2313,6 +2318,20 @@ static void __init srso_select_mitigation(void) pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n"); goto pred_cmd; } + break; + + case SRSO_CMD_IBPB_ON_VMEXIT: + if (IS_ENABLED(CONFIG_CPU_SRSO)) { + if (!boot_cpu_has(X86_FEATURE_ENTRY_IBPB) && has_microcode) { + setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT); + srso_mitigation = SRSO_MITIGATION_IBPB_ON_VMEXIT; + } + } else { + pr_err("WARNING: kernel not compiled with CPU_SRSO.\n"); + goto pred_cmd; + } + break; + default: break; } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d381ad424554..0a51fd56f960 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1498,7 +1498,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (sd->current_vmcb != svm->vmcb) { sd->current_vmcb = svm->vmcb; - indirect_branch_prediction_barrier(); + + if (!cpu_feature_enabled(X86_FEATURE_IBPB_ON_VMEXIT)) + indirect_branch_prediction_barrier(); } if (kvm_vcpu_apicv_active(vcpu)) avic_vcpu_load(vcpu, cpu); diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S index 8e8295e774f0..265452fc9ebe 100644 --- a/arch/x86/kvm/svm/vmenter.S +++ b/arch/x86/kvm/svm/vmenter.S @@ -224,6 +224,9 @@ SYM_FUNC_START(__svm_vcpu_run) */ UNTRAIN_RET + /* SRSO */ + ALTERNATIVE "", "call entry_ibpb", X86_FEATURE_IBPB_ON_VMEXIT + /* * Clear all general purpose registers except RSP and RAX to prevent * speculative use of the guest's values, even those that are reloaded -- cgit v1.2.3 From edc1e4b6e26536868ef819a735e04a5b32c10589 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 26 Jul 2023 11:10:19 +0200 Subject: s390/vmem: split pages when debug pagealloc is enabled Since commit bb1520d581a3 ("s390/mm: start kernel with DAT enabled") the kernel crashes early during boot when debug pagealloc is enabled: mem auto-init: stack:off, heap alloc:off, heap free:off addressing exception: 0005 ilc:2 [#1] SMP DEBUG_PAGEALLOC Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 6.5.0-rc3-09759-gc5666c912155 #630 [..] Krnl Code: 00000000001325f6: ec5600248064 cgrj %r5,%r6,8,000000000013263e 00000000001325fc: eb880002000c srlg %r8,%r8,2 #0000000000132602: b2210051 ipte %r5,%r1,%r0,0 >0000000000132606: b90400d1 lgr %r13,%r1 000000000013260a: 41605008 la %r6,8(%r5) 000000000013260e: a7db1000 aghi %r13,4096 0000000000132612: b221006d ipte %r6,%r13,%r0,0 0000000000132616: e3d0d0000171 lay %r13,4096(%r13) Call Trace: __kernel_map_pages+0x14e/0x320 __free_pages_ok+0x23a/0x5a8) free_low_memory_core_early+0x214/0x2c8 memblock_free_all+0x28/0x58 mem_init+0xb6/0x228 mm_core_init+0xb6/0x3b0 start_kernel+0x1d2/0x5a8 startup_continue+0x36/0x40 Kernel panic - not syncing: Fatal exception: panic_on_oops This is caused by using large mappings on machines with EDAT1/EDAT2. Add the code to split the mappings into 4k pages if debug pagealloc is enabled by CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT or the debug_pagealloc kernel command line option. Fixes: bb1520d581a3 ("s390/mm: start kernel with DAT enabled") Signed-off-by: Sven Schnelle Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens --- arch/s390/mm/vmem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index b26649233d12..24a66670f5c3 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -763,6 +763,8 @@ void __init vmem_map_init(void) if (static_key_enabled(&cpu_has_bear)) set_memory_nx(0, 1); set_memory_nx(PAGE_SIZE, 1); + if (debug_pagealloc_enabled()) + set_memory_4k(0, ident_map_size >> PAGE_SHIFT); pr_info("Write protected kernel read-only data: %luk\n", (unsigned long)(__end_rodata - _stext) >> 10); -- cgit v1.2.3 From 2608766756578629b42b54c8307c56269ca07a33 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 26 Jul 2023 15:25:33 +0200 Subject: s390: update defconfigs Changes from before and new defaults: - enable USER_EVENTS - enable FAULT_INJECTION_CONFIGFS (debug only) - disable FW_LOADER Signed-off-by: Heiko Carstens --- arch/s390/configs/debug_defconfig | 11 ++++++----- arch/s390/configs/defconfig | 9 +++++---- arch/s390/configs/zfcpdump_defconfig | 1 - 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index aa95cf6dfabb..32bf2c7b4057 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -116,7 +116,6 @@ CONFIG_UNIX=y CONFIG_UNIX_DIAG=m CONFIG_XFRM_USER=m CONFIG_NET_KEY=m -CONFIG_NET_TC_SKB_EXT=y CONFIG_SMC=m CONFIG_SMC_DIAG=m CONFIG_INET=y @@ -193,6 +192,7 @@ CONFIG_NFT_REJECT=m CONFIG_NFT_COMPAT=m CONFIG_NFT_HASH=m CONFIG_NFT_FIB_INET=m +CONFIG_NETFILTER_XTABLES_COMPAT=y CONFIG_NETFILTER_XT_SET=m CONFIG_NETFILTER_XT_TARGET_AUDIT=m CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m @@ -379,6 +379,7 @@ CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m CONFIG_NET_ACT_GATE=m +CONFIG_NET_TC_SKB_EXT=y CONFIG_DNS_RESOLVER=y CONFIG_OPENVSWITCH=m CONFIG_VSOCKETS=m @@ -395,6 +396,7 @@ CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_S390=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_SAFE=y +# CONFIG_FW_LOADER is not set CONFIG_CONNECTOR=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=m @@ -502,7 +504,6 @@ CONFIG_NLMON=m # CONFIG_NET_VENDOR_GOOGLE is not set # CONFIG_NET_VENDOR_HUAWEI is not set # CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_LITEX is not set # CONFIG_NET_VENDOR_MARVELL is not set CONFIG_MLX4_EN=m @@ -542,6 +543,7 @@ CONFIG_MLX5_CORE_EN=y # CONFIG_NET_VENDOR_TI is not set # CONFIG_NET_VENDOR_VERTEXCOM is not set # CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set CONFIG_PPP=m @@ -646,7 +648,6 @@ CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_INODE64=y CONFIG_HUGETLBFS=y -CONFIG_CONFIGFS_FS=m CONFIG_ECRYPT_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m @@ -690,7 +691,6 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_FORTIFY_SOURCE=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_SECURITY_LOCKDOWN_LSM=y CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y CONFIG_SECURITY_LANDLOCK=y @@ -744,7 +744,6 @@ CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3_GENERIC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_WP512=m @@ -844,6 +843,7 @@ CONFIG_PREEMPT_TRACER=y CONFIG_SCHED_TRACER=y CONFIG_FTRACE_SYSCALLS=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_USER_EVENTS=y CONFIG_HIST_TRIGGERS=y CONFIG_FTRACE_STARTUP_TEST=y # CONFIG_EVENT_TRACE_STARTUP_TEST is not set @@ -866,6 +866,7 @@ CONFIG_FAIL_MAKE_REQUEST=y CONFIG_FAIL_IO_TIMEOUT=y CONFIG_FAIL_FUTEX=y CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_CONFIGFS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_LKDTM=m CONFIG_TEST_MIN_HEAP=y diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index f041945f9148..f95b7c62a043 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -107,7 +107,6 @@ CONFIG_UNIX=y CONFIG_UNIX_DIAG=m CONFIG_XFRM_USER=m CONFIG_NET_KEY=m -CONFIG_NET_TC_SKB_EXT=y CONFIG_SMC=m CONFIG_SMC_DIAG=m CONFIG_INET=y @@ -184,6 +183,7 @@ CONFIG_NFT_REJECT=m CONFIG_NFT_COMPAT=m CONFIG_NFT_HASH=m CONFIG_NFT_FIB_INET=m +CONFIG_NETFILTER_XTABLES_COMPAT=y CONFIG_NETFILTER_XT_SET=m CONFIG_NETFILTER_XT_TARGET_AUDIT=m CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m @@ -369,6 +369,7 @@ CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m CONFIG_NET_ACT_GATE=m +CONFIG_NET_TC_SKB_EXT=y CONFIG_DNS_RESOLVER=y CONFIG_OPENVSWITCH=m CONFIG_VSOCKETS=m @@ -385,6 +386,7 @@ CONFIG_HOTPLUG_PCI_S390=y CONFIG_UEVENT_HELPER=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_SAFE=y +# CONFIG_FW_LOADER is not set CONFIG_CONNECTOR=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=m @@ -492,7 +494,6 @@ CONFIG_NLMON=m # CONFIG_NET_VENDOR_GOOGLE is not set # CONFIG_NET_VENDOR_HUAWEI is not set # CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_LITEX is not set # CONFIG_NET_VENDOR_MARVELL is not set CONFIG_MLX4_EN=m @@ -532,6 +533,7 @@ CONFIG_MLX5_CORE_EN=y # CONFIG_NET_VENDOR_TI is not set # CONFIG_NET_VENDOR_VERTEXCOM is not set # CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set CONFIG_PPP=m @@ -673,7 +675,6 @@ CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_SECURITY_LOCKDOWN_LSM=y CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y CONFIG_SECURITY_LANDLOCK=y @@ -729,7 +730,6 @@ CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3_GENERIC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_WP512=m @@ -793,6 +793,7 @@ CONFIG_STACK_TRACER=y CONFIG_SCHED_TRACER=y CONFIG_FTRACE_SYSCALLS=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_USER_EVENTS=y CONFIG_HIST_TRIGGERS=y CONFIG_SAMPLES=y CONFIG_SAMPLE_TRACE_PRINTK=m diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 6f68b39817ef..e62fb2015102 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -53,7 +53,6 @@ CONFIG_ZFCP=y # CONFIG_HVC_IUCV is not set # CONFIG_HW_RANDOM_S390 is not set # CONFIG_HMC_DRV is not set -# CONFIG_S390_UV_UAPI is not set # CONFIG_S390_TAPE is not set # CONFIG_VMCP is not set # CONFIG_MONWRITER is not set -- cgit v1.2.3 From 5c49b6c3f2cc6d44f691c4aa3d22ca49bedf637b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 18 Jul 2023 17:18:34 -0700 Subject: perf parse-events: Extra care around force grouped events Perf metric (topdown) events on Intel Icelake+ machines require a group, however, they may be next to events that don't require a group. Consider: cycles,slots,topdown-fe-bound The cycles event needn't be grouped but slots and topdown-fe-bound need grouping. Prior to this change, as slots and topdown-fe-bound need a group forcing and all events share the same PMU, slots and topdown-fe-bound would be forced into a group with cycles. This is a bug on two fronts, cycles wasn't supposed to be grouped and cycles can't be a group leader with a perf metric event. This change adds recognition that cycles isn't force grouped and so it shouldn't be force grouped with slots and topdown-fe-bound. Fixes: a90cc5a9eeab45ea ("perf evsel: Don't let evsel__group_pmu_name() traverse unsorted group") Signed-off-by: Ian Rogers Tested-by: Andi Kleen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230719001836.198363-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index acde097e327c..af4683526d5f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2149,7 +2149,7 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) int idx = 0, unsorted_idx = -1; struct evsel *pos, *cur_leader = NULL; struct perf_evsel *cur_leaders_grp = NULL; - bool idx_changed = false; + bool idx_changed = false, cur_leader_force_grouped = false; int orig_num_leaders = 0, num_leaders = 0; int ret; @@ -2190,7 +2190,7 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) const struct evsel *pos_leader = evsel__leader(pos); const char *pos_pmu_name = pos->group_pmu_name; const char *cur_leader_pmu_name, *pos_leader_pmu_name; - bool force_grouped = arch_evsel__must_be_in_group(pos); + bool pos_force_grouped = arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ if (pos->core.idx != idx) @@ -2206,7 +2206,8 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) cur_leader = pos; cur_leader_pmu_name = cur_leader->group_pmu_name; - if ((cur_leaders_grp != pos->core.leader && !force_grouped) || + if ((cur_leaders_grp != pos->core.leader && + (!pos_force_grouped || !cur_leader_force_grouped)) || strcmp(cur_leader_pmu_name, pos_pmu_name)) { /* Event is for a different group/PMU than last. */ cur_leader = pos; @@ -2216,9 +2217,14 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) * group. */ cur_leaders_grp = pos->core.leader; + /* + * Avoid forcing events into groups with events that + * don't need to be in the group. + */ + cur_leader_force_grouped = pos_force_grouped; } pos_leader_pmu_name = pos_leader->group_pmu_name; - if (strcmp(pos_leader_pmu_name, pos_pmu_name) || force_grouped) { + if (strcmp(pos_leader_pmu_name, pos_pmu_name) || pos_force_grouped) { /* * Event's PMU differs from its leader's. Groups can't * span PMUs, so update leader from the group/PMU -- cgit v1.2.3 From e8d38345da249be17046b74d7bb64b77cdd07a08 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 18 Jul 2023 17:18:35 -0700 Subject: perf parse-events: When fixing group leaders always set the leader The evsel grouping fix iterates over evsels tracking the leader group and the current position's group, updating the current position's leader if an evsel is being forced into a group or groups changed. However, groups changing isn't a sufficient condition as sorting may have reordered events and the leader may no longer come first. For this reason update all leaders whenever they disagree. This change breaks certain Icelake+ metrics due to bugs in the kernel. For example, tma_l3_bound with threshold enabled tries to program the events: {topdown-retiring,slots,CYCLE_ACTIVITY.STALLS_L2_MISS,topdown-fe-bound,EXE_ACTIVITY.BOUND_ON_STORES,EXE_ACTIVITY.1_PORTS_UTIL,topdown-be-bound,cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/,CYCLE_ACTIVITY.STALLS_L3_MISS,CPU_CLK_UNHALTED.THREAD,CYCLE_ACTIVITY.STALLS_MEM_ANY,EXE_ACTIVITY.2_PORTS_UTIL,CYCLE_ACTIVITY.STALLS_TOTAL,topdown-bad-spec}:W fixing the perf metric event order gives: {slots,topdown-retiring,topdown-fe-bound,topdown-be-bound,topdown-bad-spec,CYCLE_ACTIVITY.STALLS_L2_MISS,EXE_ACTIVITY.BOUND_ON_STORES,EXE_ACTIVITY.1_PORTS_UTIL,cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/,CYCLE_ACTIVITY.STALLS_L3_MISS,CPU_CLK_UNHALTED.THREAD,CYCLE_ACTIVITY.STALLS_MEM_ANY,EXE_ACTIVITY.2_PORTS_UTIL,CYCLE_ACTIVITY.STALLS_TOTAL}:W Both of these return "" for all events, whilst they work with the group removed respecting that the perf metric events must still be grouped. A vendor events update will need to add METRIC_NO_GROUP to these metrics to workaround the kernel PMU driver issue. Fixes: a90cc5a9eeab45ea ("perf evsel: Don't let evsel__group_pmu_name() traverse unsorted group") Signed-off-by: Ian Rogers Tested-by: Andi Kleen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230719001836.198363-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index af4683526d5f..62d5ff5d8dae 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2189,7 +2189,7 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) list_for_each_entry(pos, list, core.node) { const struct evsel *pos_leader = evsel__leader(pos); const char *pos_pmu_name = pos->group_pmu_name; - const char *cur_leader_pmu_name, *pos_leader_pmu_name; + const char *cur_leader_pmu_name; bool pos_force_grouped = arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ @@ -2223,13 +2223,8 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) */ cur_leader_force_grouped = pos_force_grouped; } - pos_leader_pmu_name = pos_leader->group_pmu_name; - if (strcmp(pos_leader_pmu_name, pos_pmu_name) || pos_force_grouped) { - /* - * Event's PMU differs from its leader's. Groups can't - * span PMUs, so update leader from the group/PMU - * tracker. - */ + if (pos_leader != cur_leader) { + /* The leader changed so update it. */ evsel__set_leader(pos, cur_leader); } } -- cgit v1.2.3 From b161f25fa30644598007d752a1b802cda0140788 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 18 Jul 2023 17:18:36 -0700 Subject: perf parse-events: Only move force grouped evsels when sorting Prior to this change, events without a group would be sorted as if they were from the location of the first event without a group. For example instructions and cycles are without a group: instructions,{imc_free_running/data_read/,imc_free_running/data_write/},cycles parse events would create an eventual evlist like: instructions,cycles,{uncore_imc_free_running_0/data_read/,uncore_imc_free_running_1/data_read/,uncore_imc_free_running_0/data_write/,uncore_imc_free_running_1/data_write/} This is done so that perf metric events, that must always be in a group, will be adjacent and so can be forced into a group. This change modifies the sorting so that only force grouped events, like perf metrics, are sorted and all other events keep their position with respect to groups in the evlist. The location of the force grouped event is chosen to match the first force grouped event. For architectures without force grouped events, ie anything not Intel Icelake or newer, this should mean sorting and fixing doesn't modify the event positions except when fixing the grouping for PMUs of things like uncore events. Fixes: 347c2f0a0988c59c ("perf parse-events: Sort and group parsed events") Reported-by: Andi Kleen Signed-off-by: Ian Rogers Tested-by: Andi Kleen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230719001836.198363-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 62d5ff5d8dae..c9ec0cafb69d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2100,16 +2100,16 @@ __weak int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs) return lhs->core.idx - rhs->core.idx; } -static int evlist__cmp(void *state, const struct list_head *l, const struct list_head *r) +static int evlist__cmp(void *_fg_idx, const struct list_head *l, const struct list_head *r) { const struct perf_evsel *lhs_core = container_of(l, struct perf_evsel, node); const struct evsel *lhs = container_of(lhs_core, struct evsel, core); const struct perf_evsel *rhs_core = container_of(r, struct perf_evsel, node); const struct evsel *rhs = container_of(rhs_core, struct evsel, core); - int *leader_idx = state; - int lhs_leader_idx = *leader_idx, rhs_leader_idx = *leader_idx, ret; + int *force_grouped_idx = _fg_idx; + int lhs_sort_idx, rhs_sort_idx, ret; const char *lhs_pmu_name, *rhs_pmu_name; - bool lhs_has_group = false, rhs_has_group = false; + bool lhs_has_group, rhs_has_group; /* * First sort by grouping/leader. Read the leader idx only if the evsel @@ -2121,15 +2121,25 @@ static int evlist__cmp(void *state, const struct list_head *l, const struct list */ if (lhs_core->leader != lhs_core || lhs_core->nr_members > 1) { lhs_has_group = true; - lhs_leader_idx = lhs_core->leader->idx; + lhs_sort_idx = lhs_core->leader->idx; + } else { + lhs_has_group = false; + lhs_sort_idx = *force_grouped_idx != -1 && arch_evsel__must_be_in_group(lhs) + ? *force_grouped_idx + : lhs_core->idx; } if (rhs_core->leader != rhs_core || rhs_core->nr_members > 1) { rhs_has_group = true; - rhs_leader_idx = rhs_core->leader->idx; + rhs_sort_idx = rhs_core->leader->idx; + } else { + rhs_has_group = false; + rhs_sort_idx = *force_grouped_idx != -1 && arch_evsel__must_be_in_group(rhs) + ? *force_grouped_idx + : rhs_core->idx; } - if (lhs_leader_idx != rhs_leader_idx) - return lhs_leader_idx - rhs_leader_idx; + if (lhs_sort_idx != rhs_sort_idx) + return lhs_sort_idx - rhs_sort_idx; /* Group by PMU if there is a group. Groups can't span PMUs. */ if (lhs_has_group && rhs_has_group) { @@ -2146,7 +2156,7 @@ static int evlist__cmp(void *state, const struct list_head *l, const struct list static int parse_events__sort_events_and_fix_groups(struct list_head *list) { - int idx = 0, unsorted_idx = -1; + int idx = 0, force_grouped_idx = -1; struct evsel *pos, *cur_leader = NULL; struct perf_evsel *cur_leaders_grp = NULL; bool idx_changed = false, cur_leader_force_grouped = false; @@ -2174,12 +2184,14 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) */ pos->core.idx = idx++; - if (unsorted_idx == -1 && pos == pos_leader && pos->core.nr_members < 2) - unsorted_idx = pos->core.idx; + /* Remember an index to sort all forced grouped events together to. */ + if (force_grouped_idx == -1 && pos == pos_leader && pos->core.nr_members < 2 && + arch_evsel__must_be_in_group(pos)) + force_grouped_idx = pos->core.idx; } /* Sort events. */ - list_sort(&unsorted_idx, list, evlist__cmp); + list_sort(&force_grouped_idx, list, evlist__cmp); /* * Recompute groups, splitting for PMUs and adding groups for events @@ -2190,7 +2202,8 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) const struct evsel *pos_leader = evsel__leader(pos); const char *pos_pmu_name = pos->group_pmu_name; const char *cur_leader_pmu_name; - bool pos_force_grouped = arch_evsel__must_be_in_group(pos); + bool pos_force_grouped = force_grouped_idx != -1 && + arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ if (pos->core.idx != idx) -- cgit v1.2.3 From 09eadda27ca4afc3f560efea265bbe7a93ef786d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 19 Mar 2023 22:29:28 +0100 Subject: backlight: corgi_lcd: fix missing prototype The corgi_lcd_limit_intensity() function is called from platform and defined in a driver, but the driver does not see the declaration: drivers/video/backlight/corgi_lcd.c:434:6: error: no previous prototype for 'corgi_lcd_limit_intensity' [-Werror=missing-prototypes] 434 | void corgi_lcd_limit_intensity(int limit) Move the prototype into a header that can be included from both sides to shut up the warning. Reviewed-by: Daniel Thompson Signed-off-by: Arnd Bergmann --- arch/arm/mach-pxa/sharpsl_pm.h | 1 - arch/arm/mach-pxa/spitz_pm.c | 1 + include/linux/spi/corgi_lcd.h | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/sharpsl_pm.h b/arch/arm/mach-pxa/sharpsl_pm.h index 20e4cab64d85..623167f30ec2 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.h +++ b/arch/arm/mach-pxa/sharpsl_pm.h @@ -105,5 +105,4 @@ void sharpsl_pm_led(int val); #define MAX1111_ACIN_VOLT 6u int sharpsl_pm_pxa_read_max1111(int channel); -void corgi_lcd_limit_intensity(int limit); #endif diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 1c021cef965f..8bc4ea51a0c1 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/spi/corgi_lcd.h b/include/linux/spi/corgi_lcd.h index 0b857616919c..fc6c1515dc54 100644 --- a/include/linux/spi/corgi_lcd.h +++ b/include/linux/spi/corgi_lcd.h @@ -15,4 +15,6 @@ struct corgi_lcd_platform_data { void (*kick_battery)(void); }; +void corgi_lcd_limit_intensity(int limit); + #endif /* __LINUX_SPI_CORGI_LCD_H */ -- cgit v1.2.3 From d3053b4a6b76f29fd1bf0b438b19a2d6ece9657d Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Tue, 20 Jun 2023 05:53:59 +0300 Subject: MAINTAINERS: Add myself as reviewer for HYPERBUS Add myself as Designated Reviewer for Hyperbus support. I'm assessing the framework and I'd like to get involved in reviewing further patches. Signed-off-by: Tudor Ambarus Acked-by: Vignesh Raghavendra Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230620025359.33839-1-tudor.ambarus@linaro.org --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc..c5e338ca3b52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9649,6 +9649,7 @@ F: tools/hv/ HYPERBUS SUPPORT M: Vignesh Raghavendra +R: Tudor Ambarus L: linux-mtd@lists.infradead.org S: Supported Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -- cgit v1.2.3 From 71c8f9cf2623d0db79665f876b95afcdd8214aec Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 19 Jul 2023 21:00:25 +0200 Subject: mtd: spi-nor: avoid holes in struct spi_mem_op gcc gets confused when -ftrivial-auto-var-init=pattern is used on sparse bit fields such as 'struct spi_mem_op', which caused the previous false positive warning about an uninitialized variable: drivers/mtd/spi-nor/spansion.c: error: 'op' is used uninitialized [-Werror=uninitialized] In fact, the variable is fully initialized and gcc does not see it being used, so the warning is entirely bogus. The problem appears to be a misoptimization in the initialization of single bit fields when the rest of the bytes are not initialized. A previous workaround added another initialization, which ended up shutting up the warning in spansion.c, though it apparently still happens in other files as reported by Peter Foley in the gcc bugzilla. The workaround of adding a fake initialization seems particularly bad because it would set values that can never be correct but prevent the compiler from warning about actually missing initializations. Revert the broken workaround and instead pad the structure to only have bitfields that add up to full bytes, which should avoid this behavior in all drivers. I also filed a new bug against gcc with what I found, so this can hopefully be addressed in future gcc releases. At the moment, only gcc-12 and gcc-13 are affected. Cc: Peter Foley Cc: Pedro Falcato Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110743 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108402 Link: https://godbolt.org/z/efMMsG1Kx Fixes: 420c4495b5e56 ("mtd: spi-nor: spansion: make sure local struct does not contain garbage") Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Acked-by: Tudor Ambarus Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230719190045.4007391-1-arnd@kernel.org --- drivers/mtd/spi-nor/spansion.c | 4 ++-- include/linux/spi/spi-mem.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 36876aa849ed..15f9a80c10b9 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -361,7 +361,7 @@ static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor, */ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) { - struct spi_mem_op op = {}; + struct spi_mem_op op; u8 addr_mode; int ret; @@ -492,7 +492,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt) { - struct spi_mem_op op = {}; + struct spi_mem_op op; int ret; ret = cypress_nor_set_addr_mode_nbytes(nor); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 8e984d75f5b6..6b0a7dc48a4b 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -101,6 +101,7 @@ struct spi_mem_op { u8 nbytes; u8 buswidth; u8 dtr : 1; + u8 __pad : 7; u16 opcode; } cmd; @@ -108,6 +109,7 @@ struct spi_mem_op { u8 nbytes; u8 buswidth; u8 dtr : 1; + u8 __pad : 7; u64 val; } addr; @@ -115,12 +117,14 @@ struct spi_mem_op { u8 nbytes; u8 buswidth; u8 dtr : 1; + u8 __pad : 7; } dummy; struct { u8 buswidth; u8 dtr : 1; u8 ecc : 1; + u8 __pad : 6; enum spi_mem_data_dir dir; unsigned int nbytes; union { -- cgit v1.2.3 From c6abce60338aa2080973cd95be0aedad528bb41f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 19 Jul 2023 23:55:01 +0200 Subject: mtd: rawnand: fsl_upm: Fix an off-by one test in fun_exec_op() 'op-cs' is copied in 'fun->mchip_number' which is used to access the 'mchip_offsets' and the 'rnb_gpio' arrays. These arrays have NAND_MAX_CHIPS elements, so the index must be below this limit. Fix the sanity check in order to avoid the NAND_MAX_CHIPS value. This would lead to out-of-bound accesses. Fixes: 54309d657767 ("mtd: rawnand: fsl_upm: Implement exec_op()") Signed-off-by: Christophe JAILLET Reviewed-by: Dan Carpenter Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/cd01cba1c7eda58bdabaae174c78c067325803d2.1689803636.git.christophe.jaillet@wanadoo.fr --- drivers/mtd/nand/raw/fsl_upm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 086426139173..7366e85c09fd 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -135,7 +135,7 @@ static int fun_exec_op(struct nand_chip *chip, const struct nand_operation *op, unsigned int i; int ret; - if (op->cs > NAND_MAX_CHIPS) + if (op->cs >= NAND_MAX_CHIPS) return -EINVAL; if (check_only) -- cgit v1.2.3 From bcc29b7f5af6797702c2306a7aacb831fc5ce9cb Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Tue, 25 Jul 2023 10:33:30 +0800 Subject: bpf: Add length check for SK_DIAG_BPF_STORAGE_REQ_MAP_FD parsing The nla_for_each_nested parsing in function bpf_sk_storage_diag_alloc does not check the length of the nested attribute. This can lead to an out-of-attribute read and allow a malformed nlattr (e.g., length 0) to be viewed as a 4 byte integer. This patch adds an additional check when the nlattr is getting counted. This makes sure the latter nla_get_u32 can access the attributes with the correct length. Fixes: 1ed4d92458a9 ("bpf: INET_DIAG support in bpf_sk_storage") Suggested-by: Jakub Kicinski Signed-off-by: Lin Ma Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20230725023330.422856-1-linma@zju.edu.cn Signed-off-by: Martin KaFai Lau --- net/core/bpf_sk_storage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c index d4172534dfa8..cca7594be92e 100644 --- a/net/core/bpf_sk_storage.c +++ b/net/core/bpf_sk_storage.c @@ -496,8 +496,11 @@ bpf_sk_storage_diag_alloc(const struct nlattr *nla_stgs) return ERR_PTR(-EPERM); nla_for_each_nested(nla, nla_stgs, rem) { - if (nla_type(nla) == SK_DIAG_BPF_STORAGE_REQ_MAP_FD) + if (nla_type(nla) == SK_DIAG_BPF_STORAGE_REQ_MAP_FD) { + if (nla_len(nla) != sizeof(u32)) + return ERR_PTR(-EINVAL); nr_maps++; + } } diag = kzalloc(struct_size(diag, maps, nr_maps), GFP_KERNEL); -- cgit v1.2.3 From cdddb626dc053a2bbe8be4150e9b67395130a683 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 1 Jul 2023 11:17:22 -0600 Subject: media: venus: Use struct_size_t() helper in pkt_session_unset_buffers() Prefer struct_size_t() over struct_size() when no pointer instance of the structure type is present. Signed-off-by: "Gustavo A. R. Silva" Reviewed-by: Vikash Garodia Link: https://lore.kernel.org/r/ZKBfoqSl61jfpO2r@work Signed-off-by: Kees Cook --- drivers/media/platform/qcom/venus/hfi_cmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 7f0802a5518c..3418d2dd9371 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -251,8 +251,8 @@ int pkt_session_unset_buffers(struct hfi_session_release_buffer_pkt *pkt, pkt->extradata_size = 0; pkt->shdr.hdr.size = - struct_size((struct hfi_session_set_buffers_pkt *)0, - buffer_info, bd->num_buffers); + struct_size_t(struct hfi_session_set_buffers_pkt, + buffer_info, bd->num_buffers); } pkt->response_req = bd->response_required; -- cgit v1.2.3 From c8af46580b0f5300bb3df16b89f795f255cbcb65 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:27 +0100 Subject: ASoC: sta32x: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the sta32x driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-1-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 4a694d0bfd68..34ffd32ab9dc 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1022,7 +1022,7 @@ static const struct regmap_config sta32x_regmap = { .max_register = STA32X_FDRC2, .reg_defaults = sta32x_regs, .num_reg_defaults = ARRAY_SIZE(sta32x_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta32x_write_regs, .rd_table = &sta32x_read_regs, .volatile_table = &sta32x_volatile_regs, -- cgit v1.2.3 From 87256942e90242ec7ddeeba9f6b9433f01eec9be Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:28 +0100 Subject: ASoC: sta350: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the sta350 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-2-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta350.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index d05f3fd57661..e4a9e9241c60 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1065,7 +1065,7 @@ static const struct regmap_config sta350_regmap = { .max_register = STA350_MISC2, .reg_defaults = sta350_regs, .num_reg_defaults = ARRAY_SIZE(sta350_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta350_write_regs, .rd_table = &sta350_read_regs, .volatile_table = &sta350_volatile_regs, -- cgit v1.2.3 From 35959958df14542c68b0d0c1a7906838323fcbeb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:29 +0100 Subject: ASoC: sta529: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the sta529 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-3-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0ac08478ddac..eedafef775e5 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -331,7 +331,7 @@ static const struct regmap_config sta529_regmap = { .max_register = STA529_MAX_REGISTER, .readable_reg = sta529_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = sta529_reg_defaults, .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; -- cgit v1.2.3 From 4810c775484b373ec5c1c75f53bb9a09ba96a7ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:30 +0100 Subject: ASoC: stac9766: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the stac9766 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-4-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 1824a71fe053..2f9f10a4dfed 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x78, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, -- cgit v1.2.3 From 66b1abc17c9d9e4af58098b9d6b8d7ade961e195 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:31 +0100 Subject: ASoC: sti-sas: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the sti-sas driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-5-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 99545bcb2ba9..c421906a0694 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -316,7 +316,7 @@ static const struct regmap_config stih407_sas_regmap = { .reg_defaults = stih407_sas_reg_defaults, .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), .volatile_reg = sti_sas_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_read = sti_sas_read_reg, .reg_write = sti_sas_write_reg, }; -- cgit v1.2.3 From 8f59c7ed230784ca914c98e250c65768b71d5de4 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 27 Jul 2023 10:16:32 +0800 Subject: ASoC: rt1017: Remove unused function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function are defined in the rt1017-sdca-sdw.h file, but not called elsewhere, so delete the unused functions. sound/soc/codecs/rt1017-sdca-sdw.h:183:33: warning: ‘rt1017_sdca_mbq_defaults’ defined but not used. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5998 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230727021632.88912-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1017-sdca-sdw.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h index 5968b9a7d124..4932b5dbe3c0 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.h +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -180,9 +180,4 @@ static const struct reg_default rt1017_sdca_reg_defaults[] = { RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, }; -static const struct reg_default rt1017_sdca_mbq_defaults[] = { - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, - RT1017_SDCA_CTL_FU_VOLUME, 0x01), 0x00 }, -}; - #endif /* __RT1017_SDW_H__ */ -- cgit v1.2.3 From d73ef2d69c0dba5f5a1cb9600045c873bab1fb7f Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Wed, 26 Jul 2023 15:53:14 +0800 Subject: rtnetlink: let rtnl_bridge_setlink checks IFLA_BRIDGE_MODE length There are totally 9 ndo_bridge_setlink handlers in the current kernel, which are 1) bnxt_bridge_setlink, 2) be_ndo_bridge_setlink 3) i40e_ndo_bridge_setlink 4) ice_bridge_setlink 5) ixgbe_ndo_bridge_setlink 6) mlx5e_bridge_setlink 7) nfp_net_bridge_setlink 8) qeth_l2_bridge_setlink 9) br_setlink. By investigating the code, we find that 1-7 parse and use nlattr IFLA_BRIDGE_MODE but 3 and 4 forget to do the nla_len check. This can lead to an out-of-attribute read and allow a malformed nlattr (e.g., length 0) to be viewed as a 2 byte integer. To avoid such issues, also for other ndo_bridge_setlink handlers in the future. This patch adds the nla_len check in rtnl_bridge_setlink and does an early error return if length mismatches. To make it works, the break is removed from the parsing for IFLA_BRIDGE_FLAGS to make sure this nla_for_each_nested iterates every attribute. Fixes: b1edc14a3fbf ("ice: Implement ice_bridge_getlink and ice_bridge_setlink") Fixes: 51616018dd1b ("i40e: Add support for getlink, setlink ndo ops") Suggested-by: Jakub Kicinski Signed-off-by: Lin Ma Acked-by: Nikolay Aleksandrov Reviewed-by: Hangbin Liu Link: https://lore.kernel.org/r/20230726075314.1059224-1-linma@zju.edu.cn Signed-off-by: Jakub Kicinski --- net/core/rtnetlink.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 3ad4e030846d..aef25aa5cf1d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -5140,13 +5140,17 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); if (br_spec) { nla_for_each_nested(attr, br_spec, rem) { - if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { + if (nla_type(attr) == IFLA_BRIDGE_FLAGS && !have_flags) { if (nla_len(attr) < sizeof(flags)) return -EINVAL; have_flags = true; flags = nla_get_u16(attr); - break; + } + + if (nla_type(attr) == IFLA_BRIDGE_MODE) { + if (nla_len(attr) < sizeof(u16)) + return -EINVAL; } } } -- cgit v1.2.3 From 9945c1fb03a3c9f7e0dcf9aa17041a70e551387a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 26 Jul 2023 15:45:16 +0100 Subject: net: dsa: fix older DSA drivers using phylink Older DSA drivers that do not provide an dsa_ops adjust_link method end up using phylink. Unfortunately, a recent phylink change that requires its supported_interfaces bitmap to be filled breaks these drivers because the bitmap remains empty. Rather than fixing each driver individually, fix it in the core code so we have a sensible set of defaults. Reported-by: Sergei Antonov Fixes: de5c9bf40c45 ("net: phylink: require supported_interfaces to be filled") Signed-off-by: Russell King (Oracle) Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean # dsa_loop Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/E1qOflM-001AEz-D3@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- net/dsa/port.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index 0ce8fd311c78..2f6195d7b741 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -1727,8 +1727,15 @@ int dsa_port_phylink_create(struct dsa_port *dp) ds->ops->phylink_mac_an_restart) dp->pl_config.legacy_pre_march2020 = true; - if (ds->ops->phylink_get_caps) + if (ds->ops->phylink_get_caps) { ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); + } else { + /* For legacy drivers */ + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + dp->pl_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_GMII, + dp->pl_config.supported_interfaces); + } pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode, &dsa_port_phylink_mac_ops); -- cgit v1.2.3 From fa467226669c09520bfb3e67fca5aeff947cdf17 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 26 Jul 2023 08:11:20 -0700 Subject: MAINTAINERS: stmmac: retire Giuseppe Cavallaro I tried to get stmmac maintainers to be more active by agreeing with them off-list on a review rotation. I pinged Peppe 3 times over 2 weeks during his "shift month", no reviews are flowing. All the contributions are much appreciated! But stmmac is quite active, we need participating maintainers :( Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230726151120.1649474-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d516295978a4..20f6174d9747 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20403,7 +20403,6 @@ F: drivers/pwm/pwm-stm32* F: include/linux/*/stm32-*tim* STMMAC ETHERNET DRIVER -M: Giuseppe Cavallaro M: Alexandre Torgue M: Jose Abreu L: netdev@vger.kernel.org -- cgit v1.2.3 From 4d50e50045aa46d9f3e578ed2edea9bd0a123d24 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 26 Jul 2023 14:58:15 +0000 Subject: net: flower: fix stack-out-of-bounds in fl_set_key_cfm() Typical misuse of nla_parse_nested(array, XXX_MAX, ...); array must be declared as struct nlattr *array[XXX_MAX + 1]; v2: Based on feedbacks from Ido Schimmel and Zahari Doychev, I also changed TCA_FLOWER_KEY_CFM_OPT_MAX and cfm_opt_policy definitions. syzbot reported: BUG: KASAN: stack-out-of-bounds in __nla_validate_parse+0x136/0x2bd0 lib/nlattr.c:588 Write of size 32 at addr ffffc90003a0ee20 by task syz-executor296/5014 CPU: 0 PID: 5014 Comm: syz-executor296 Not tainted 6.5.0-rc2-syzkaller-00307-gd192f5382581 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/12/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1e7/0x2d0 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:364 [inline] print_report+0x163/0x540 mm/kasan/report.c:475 kasan_report+0x175/0x1b0 mm/kasan/report.c:588 kasan_check_range+0x27e/0x290 mm/kasan/generic.c:187 __asan_memset+0x23/0x40 mm/kasan/shadow.c:84 __nla_validate_parse+0x136/0x2bd0 lib/nlattr.c:588 __nla_parse+0x40/0x50 lib/nlattr.c:700 nla_parse_nested include/net/netlink.h:1262 [inline] fl_set_key_cfm+0x1e3/0x440 net/sched/cls_flower.c:1718 fl_set_key+0x2168/0x6620 net/sched/cls_flower.c:1884 fl_tmplt_create+0x1fe/0x510 net/sched/cls_flower.c:2666 tc_chain_tmplt_add net/sched/cls_api.c:2959 [inline] tc_ctl_chain+0x131d/0x1ac0 net/sched/cls_api.c:3068 rtnetlink_rcv_msg+0x82b/0xf50 net/core/rtnetlink.c:6424 netlink_rcv_skb+0x1df/0x430 net/netlink/af_netlink.c:2549 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0x7c3/0x990 net/netlink/af_netlink.c:1365 netlink_sendmsg+0xa2a/0xd60 net/netlink/af_netlink.c:1914 sock_sendmsg_nosec net/socket.c:725 [inline] sock_sendmsg net/socket.c:748 [inline] ____sys_sendmsg+0x592/0x890 net/socket.c:2494 ___sys_sendmsg net/socket.c:2548 [inline] __sys_sendmsg+0x2b0/0x3a0 net/socket.c:2577 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f54c6150759 Code: 48 83 c4 28 c3 e8 d7 19 00 00 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffe06c30578 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007f54c619902d RCX: 00007f54c6150759 RDX: 0000000000000000 RSI: 0000000020000280 RDI: 0000000000000003 RBP: 00007ffe06c30590 R08: 0000000000000000 R09: 00007ffe06c305f0 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f54c61c35f0 R13: 00007ffe06c30778 R14: 0000000000000001 R15: 0000000000000001 The buggy address belongs to stack of task syz-executor296/5014 and is located at offset 32 in frame: fl_set_key_cfm+0x0/0x440 net/sched/cls_flower.c:374 This frame has 1 object: [32, 56) 'nla_cfm_opt' The buggy address belongs to the virtual mapping at [ffffc90003a08000, ffffc90003a11000) created by: copy_process+0x5c8/0x4290 kernel/fork.c:2330 Fixes: 7cfffd5fed3e ("net: flower: add support for matching cfm fields") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Simon Horman Reviewed-by: Ido Schimmel Reviewed-by: Zahari Doychev Link: https://lore.kernel.org/r/20230726145815.943910-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/uapi/linux/pkt_cls.h | 4 +++- net/sched/cls_flower.c | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 7865f5a9885b..4f3932bb712d 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -710,9 +710,11 @@ enum { TCA_FLOWER_KEY_CFM_OPT_UNSPEC, TCA_FLOWER_KEY_CFM_MD_LEVEL, TCA_FLOWER_KEY_CFM_OPCODE, - TCA_FLOWER_KEY_CFM_OPT_MAX, + __TCA_FLOWER_KEY_CFM_OPT_MAX, }; +#define TCA_FLOWER_KEY_CFM_OPT_MAX (__TCA_FLOWER_KEY_CFM_OPT_MAX - 1) + #define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */ /* Match-all classifier */ diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 8da9d039d964..9f0711da9c95 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -776,7 +776,8 @@ mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = { [TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL] = { .type = NLA_U32 }, }; -static const struct nla_policy cfm_opt_policy[TCA_FLOWER_KEY_CFM_OPT_MAX] = { +static const struct nla_policy +cfm_opt_policy[TCA_FLOWER_KEY_CFM_OPT_MAX + 1] = { [TCA_FLOWER_KEY_CFM_MD_LEVEL] = NLA_POLICY_MAX(NLA_U8, FLOW_DIS_CFM_MDL_MAX), [TCA_FLOWER_KEY_CFM_OPCODE] = { .type = NLA_U8 }, @@ -1709,7 +1710,7 @@ static int fl_set_key_cfm(struct nlattr **tb, struct fl_flow_key *mask, struct netlink_ext_ack *extack) { - struct nlattr *nla_cfm_opt[TCA_FLOWER_KEY_CFM_OPT_MAX]; + struct nlattr *nla_cfm_opt[TCA_FLOWER_KEY_CFM_OPT_MAX + 1]; int err; if (!tb[TCA_FLOWER_KEY_CFM]) -- cgit v1.2.3 From dadc5b86cc9459581f37fe755b431adc399ea393 Mon Sep 17 00:00:00 2001 From: Yuanjun Gong Date: Thu, 27 Jul 2023 01:05:06 +0800 Subject: net: dsa: fix value check in bcm_sf2_sw_probe() in bcm_sf2_sw_probe(), check the return value of clk_prepare_enable() and return the error code if clk_prepare_enable() returns an unexpected value. Fixes: e9ec5c3bd238 ("net: dsa: bcm_sf2: request and handle clocks") Signed-off-by: Yuanjun Gong Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230726170506.16547-1-ruc_gongyuanjun@163.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/bcm_sf2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index cde253d27bd0..72374b066f64 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1436,7 +1436,9 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; priv->clk_mdiv = devm_clk_get_optional(&pdev->dev, "sw_switch_mdiv"); if (IS_ERR(priv->clk_mdiv)) { @@ -1444,7 +1446,9 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) goto out_clk; } - clk_prepare_enable(priv->clk_mdiv); + ret = clk_prepare_enable(priv->clk_mdiv); + if (ret) + goto out_clk; ret = bcm_sf2_sw_rst(priv); if (ret) { -- cgit v1.2.3 From 6722b25712054c0f903b839b8f5088438dd04df3 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 24 Jul 2023 23:43:20 +0530 Subject: powerpc/mm/altmap: Fix altmap boundary check altmap->free includes the entire free space from which altmap blocks can be allocated. So when checking whether the kernel is doing altmap block free, compute the boundary correctly, otherwise memory hotunplug can fail. Fixes: 9ef34630a461 ("powerpc/mm: Fallback to RAM if the altmap is unusable") Signed-off-by: "Aneesh Kumar K.V" Reviewed-by: David Hildenbrand Signed-off-by: Michael Ellerman Link: https://msgid.link/20230724181320.471386-1-aneesh.kumar@linux.ibm.com --- arch/powerpc/mm/init_64.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index fe1b83020e0d..0ec5b45b1e86 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -314,8 +314,7 @@ void __ref vmemmap_free(unsigned long start, unsigned long end, start = ALIGN_DOWN(start, page_size); if (altmap) { alt_start = altmap->base_pfn; - alt_end = altmap->base_pfn + altmap->reserve + - altmap->free + altmap->alloc + altmap->align; + alt_end = altmap->base_pfn + altmap->reserve + altmap->free; } pr_debug("vmemmap_free %lx...%lx\n", start, end); -- cgit v1.2.3 From 5416d7925e6ee72bf1d35cad1957c9a194554da4 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 26 Jul 2023 10:06:15 +0300 Subject: dt-bindings: net: rockchip-dwmac: fix {tx|rx}-delay defaults/range in schema The range and the defaults are specified in the description instead of being specified in the schema. Fix it by adding the default value in the `default` field and specifying the range as `minimum` and `maximum`. Fixes: b331b8ef86f0 ("dt-bindings: net: convert rockchip-dwmac to json-schema") Signed-off-by: Eugen Hristev Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/rockchip-dwmac.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml index 176ea5f90251..7f324c6da915 100644 --- a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml @@ -91,12 +91,18 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle tx_delay: - description: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default. + description: Delay value for TXD timing. $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 0x7F + default: 0x30 rx_delay: - description: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default. + description: Delay value for RXD timing. $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 0x7F + default: 0x10 phy-supply: description: PHY regulator -- cgit v1.2.3 From 41a506ef71eb38d94fe133f565c87c3e06ccc072 Mon Sep 17 00:00:00 2001 From: Naveen N Rao Date: Wed, 21 Jun 2023 10:43:49 +0530 Subject: powerpc/ftrace: Create a dummy stackframe to fix stack unwind With ppc64 -mprofile-kernel and ppc32 -pg, profiling instructions to call into ftrace are emitted right at function entry. The instruction sequence used is minimal to reduce overhead. Crucially, a stackframe is not created for the function being traced. This breaks stack unwinding since the function being traced does not have a stackframe for itself. As such, it never shows up in the backtrace: /sys/kernel/debug/tracing # echo 1 > /proc/sys/kernel/stack_tracer_enabled /sys/kernel/debug/tracing # cat stack_trace Depth Size Location (17 entries) ----- ---- -------- 0) 4144 32 ftrace_call+0x4/0x44 1) 4112 432 get_page_from_freelist+0x26c/0x1ad0 2) 3680 496 __alloc_pages+0x290/0x1280 3) 3184 336 __folio_alloc+0x34/0x90 4) 2848 176 vma_alloc_folio+0xd8/0x540 5) 2672 272 __handle_mm_fault+0x700/0x1cc0 6) 2400 208 handle_mm_fault+0xf0/0x3f0 7) 2192 80 ___do_page_fault+0x3e4/0xbe0 8) 2112 160 do_page_fault+0x30/0xc0 9) 1952 256 data_access_common_virt+0x210/0x220 10) 1696 400 0xc00000000f16b100 11) 1296 384 load_elf_binary+0x804/0x1b80 12) 912 208 bprm_execve+0x2d8/0x7e0 13) 704 64 do_execveat_common+0x1d0/0x2f0 14) 640 160 sys_execve+0x54/0x70 15) 480 64 system_call_exception+0x138/0x350 16) 416 416 system_call_common+0x160/0x2c4 Fix this by having ftrace create a dummy stackframe for the function being traced. With this, backtraces now capture the function being traced: /sys/kernel/debug/tracing # cat stack_trace Depth Size Location (17 entries) ----- ---- -------- 0) 3888 32 _raw_spin_trylock+0x8/0x70 1) 3856 576 get_page_from_freelist+0x26c/0x1ad0 2) 3280 64 __alloc_pages+0x290/0x1280 3) 3216 336 __folio_alloc+0x34/0x90 4) 2880 176 vma_alloc_folio+0xd8/0x540 5) 2704 416 __handle_mm_fault+0x700/0x1cc0 6) 2288 96 handle_mm_fault+0xf0/0x3f0 7) 2192 48 ___do_page_fault+0x3e4/0xbe0 8) 2144 192 do_page_fault+0x30/0xc0 9) 1952 608 data_access_common_virt+0x210/0x220 10) 1344 16 0xc0000000334bbb50 11) 1328 416 load_elf_binary+0x804/0x1b80 12) 912 64 bprm_execve+0x2d8/0x7e0 13) 848 176 do_execveat_common+0x1d0/0x2f0 14) 672 192 sys_execve+0x54/0x70 15) 480 64 system_call_exception+0x138/0x350 16) 416 416 system_call_common+0x160/0x2c4 This results in two additional stores in the ftrace entry code, but produces reliable backtraces. Fixes: 153086644fd1 ("powerpc/ftrace: Add support for -mprofile-kernel ftrace ABI") Cc: stable@vger.kernel.org Signed-off-by: Naveen N Rao Signed-off-by: Michael Ellerman Link: https://msgid.link/20230621051349.759567-1-naveen@kernel.org --- arch/powerpc/kernel/trace/ftrace_mprofile.S | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/trace/ftrace_mprofile.S b/arch/powerpc/kernel/trace/ftrace_mprofile.S index ffb1db386849..1f7d86de1538 100644 --- a/arch/powerpc/kernel/trace/ftrace_mprofile.S +++ b/arch/powerpc/kernel/trace/ftrace_mprofile.S @@ -33,6 +33,9 @@ * and then arrange for the ftrace function to be called. */ .macro ftrace_regs_entry allregs + /* Create a minimal stack frame for representing B */ + PPC_STLU r1, -STACK_FRAME_MIN_SIZE(r1) + /* Create our stack frame + pt_regs */ PPC_STLU r1,-SWITCH_FRAME_SIZE(r1) @@ -42,7 +45,7 @@ #ifdef CONFIG_PPC64 /* Save the original return address in A's stack frame */ - std r0, LRSAVE+SWITCH_FRAME_SIZE(r1) + std r0, LRSAVE+SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE(r1) /* Ok to continue? */ lbz r3, PACA_FTRACE_ENABLED(r13) cmpdi r3, 0 @@ -77,6 +80,8 @@ mflr r7 /* Save it as pt_regs->nip */ PPC_STL r7, _NIP(r1) + /* Also save it in B's stackframe header for proper unwind */ + PPC_STL r7, LRSAVE+SWITCH_FRAME_SIZE(r1) /* Save the read LR in pt_regs->link */ PPC_STL r0, _LINK(r1) @@ -142,7 +147,7 @@ #endif /* Pop our stack frame */ - addi r1, r1, SWITCH_FRAME_SIZE + addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE #ifdef CONFIG_LIVEPATCH_64 /* Based on the cmpd above, if the NIP was altered handle livepatch */ -- cgit v1.2.3 From a9a65b87a5553a4ecabad7093ef6a1088bb71b88 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:46:13 +0000 Subject: ASoC: 88pm860x: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ always the case for `strncpy`! In this case, though, there was care taken to ensure that the destination buffer would be NUL-terminated. The destination buffer is zero-initialized and each `pm860x->name[i]` has a size of `MAX_NAME_LENGTH + 1`. This means that there is unlikely to be a bug here. However, in an attempt to eliminate the usage of the `strncpy` API as well as disambiguate implementations, replacements such as: `strscpy`, `strscpy_pad`, `strtomem` and `strtomem_pad` should be preferred. We are able to eliminate the need for `len + 1` since `strscpy` guarantees NUL-termination for its destination buffer as per its implementation [3]: | /* Hit buffer length without finding a NUL; force NUL-termination. */ | if (res) | dest[res-1] = '\0'; [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [3]: https://elixir.bootlin.com/linux/v6.3/source/lib/string.c#L183 Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230727-sound-soc-codecs-v1-1-562fa2836bf4@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 3574c68e0dda..d99b674d574b 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -143,7 +143,7 @@ struct pm860x_priv { struct pm860x_det det; int irq[4]; - unsigned char name[4][MAX_NAME_LEN+1]; + unsigned char name[4][MAX_NAME_LEN]; }; /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */ @@ -1373,7 +1373,7 @@ static int pm860x_codec_probe(struct platform_device *pdev) return -EINVAL; } pm860x->irq[i] = res->start + chip->irq_base; - strncpy(pm860x->name[i], res->name, MAX_NAME_LEN); + strscpy(pm860x->name[i], res->name, MAX_NAME_LEN); } ret = devm_snd_soc_register_component(&pdev->dev, -- cgit v1.2.3 From 7eb10bfbbae6025cb7b4bba3db0c1281eac05862 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:26:41 +0000 Subject: ASoC: fsl_micfil: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ always the case for `strncpy`! In this case, though, there was great care taken to ensure that the destination buffer would be NUL-terminated through the use of `len - 1` ensuring that the previously zero-initialized buffer would not overwrite the last NUL byte. This means that there's no bug here. However, `strscpy` will add a mandatory NUL byte to the destination buffer as promised by the following `strscpy` implementation [3]: | /* Hit buffer length without finding a NUL; force NUL-termination. */ | if (res) | dest[res-1] = '\0'; This means we can lose the `- 1` which clears up whats happening here. All the while, we get one step closer to eliminating the ambiguous `strncpy` api in favor of its less ambiguous replacement like `strscpy`, `strscpy_pad`, `strtomem` and `strtomem_pad` amongst others. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [3]: https://elixir.bootlin.com/linux/v6.3/source/lib/string.c#L183 Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230727-sound-soc-fsl-v1-1-4fc0ed7e0366@google.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 3f08082a55be..fe28b27e50d0 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1044,7 +1044,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) return -ENOMEM; micfil->pdev = pdev; - strncpy(micfil->name, np->name, sizeof(micfil->name) - 1); + strscpy(micfil->name, np->name, sizeof(micfil->name)); micfil->soc = of_device_get_match_data(&pdev->dev); -- cgit v1.2.3 From ee31742bf17636da1304af77b2cb1c29b5dda642 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 15 May 2023 09:21:37 +0200 Subject: drm/imx/ipuv3: Fix front porch adjustment upon hactive aligning When hactive is not aligned to 8 pixels, it is aligned accordingly and hfront porch needs to be reduced the same amount. Unfortunately the front porch is set to the difference rather than reducing it. There are some Samsung TVs which can't cope with a front porch of instead of 70. Fixes: 94dfec48fca7 ("drm/imx: Add 8 pixel alignment fix") Signed-off-by: Alexander Stein Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20230515072137.116211-1-alexander.stein@ew.tq-group.com [p.zabel@pengutronix.de: Fixed subject] Signed-off-by: Philipp Zabel Link: https://patchwork.freedesktop.org/patch/msgid/20230515072137.116211-1-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index 5f26090b0c98..89585b31b985 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -310,7 +310,7 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", sig_cfg.mode.hactive, new_hactive); - sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive; + sig_cfg.mode.hfront_porch -= new_hactive - sig_cfg.mode.hactive; sig_cfg.mode.hactive = new_hactive; } -- cgit v1.2.3 From 74158a8cad79d2f5dcf71508993664c5cfcbfa3c Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 28 Jul 2023 00:08:24 +0000 Subject: KVM: arm64: Skip instruction after emulating write to TCR_EL1 Whelp, this is embarrassing. Since commit 082fdfd13841 ("KVM: arm64: Prevent guests from enabling HA/HD on Ampere1") KVM traps writes to TCR_EL1 on AmpereOne to work around an erratum in the unadvertised HAFDBS implementation, preventing the guest from enabling the feature. Unfortunately, I failed virtualization 101 when working on that change, and forgot to advance PC after instruction emulation. Do the right thing and skip the MSR instruction after emulating the write. Fixes: 082fdfd13841 ("KVM: arm64: Prevent guests from enabling HA/HD on Ampere1") Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20230728000824.3848025-1-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/include/hyp/switch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 4bddb8541bec..34f222af6165 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -457,6 +457,7 @@ static bool handle_ampere1_tcr(struct kvm_vcpu *vcpu) */ val &= ~(TCR_HD | TCR_HA); write_sysreg_el1(val, SYS_TCR); + __kvm_skip_instr(vcpu); return true; } -- cgit v1.2.3 From 98ce8e4a9dcfb448b30a2d7a16190f4a00382377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georg=20M=C3=BCller?= Date: Fri, 28 Jul 2023 17:18:12 +0200 Subject: perf test uprobe_from_different_cu: Skip if there is no gcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without gcc, the test will fail. On cleanup, ignore probe removal errors. Otherwise, in case of an error adding the probe, the temporary directory is not removed. Fixes: 56cbeacf14353057 ("perf probe: Add test for regression introduced by switch to die_get_decl_file()") Signed-off-by: Georg MĂŒller Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Georg MĂŒller Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230728151812.454806-2-georgmueller@gmx.net Link: https://lore.kernel.org/r/CAP-5=fUP6UuLgRty3t2=fQsQi3k4hDMz415vWdp1x88QMvZ8ug@mail.gmail.com/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_uprobe_from_different_cu.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_uprobe_from_different_cu.sh b/tools/perf/tests/shell/test_uprobe_from_different_cu.sh index 00d2e0e2e0c2..319f36ebb9a4 100755 --- a/tools/perf/tests/shell/test_uprobe_from_different_cu.sh +++ b/tools/perf/tests/shell/test_uprobe_from_different_cu.sh @@ -4,6 +4,12 @@ set -e +# skip if there's no gcc +if ! [ -x "$(command -v gcc)" ]; then + echo "failed: no gcc compiler" + exit 2 +fi + temp_dir=$(mktemp -d /tmp/perf-uprobe-different-cu-sh.XXXXXXXXXX) cleanup() @@ -11,7 +17,7 @@ cleanup() trap - EXIT TERM INT if [[ "${temp_dir}" =~ ^/tmp/perf-uprobe-different-cu-sh.*$ ]]; then echo "--- Cleaning up ---" - perf probe -x ${temp_dir}/testfile -d foo + perf probe -x ${temp_dir}/testfile -d foo || true rm -f "${temp_dir}/"* rmdir "${temp_dir}" fi -- cgit v1.2.3 From 0fcde5989e8a54b2a155d8bcea21a7f99abb50f9 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 25 Jul 2023 22:19:38 -0700 Subject: cxl/memdev: Improve sanitize ABI descriptions Be more detailed about the CPU cache management situation. The same goes for both sanitize and secure erase. Signed-off-by: Davidlohr Bueso Link: https://lore.kernel.org/r/20230726051940.3570-2-dave@stgolabs.net Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- Documentation/ABI/testing/sysfs-bus-cxl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index 6350dd82b9a9..c4c4acb1f3b3 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -82,7 +82,11 @@ Description: whether it resides in persistent capacity, volatile capacity, or the LSA, is made permanently unavailable by whatever means is appropriate for the media type. This functionality requires - the device to be not be actively decoding any HPA ranges. + the device to be disabled, that is, not actively decoding any + HPA ranges. This permits avoiding explicit global CPU cache + management, relying instead for it to be done when a region + transitions between software programmed and hardware committed + states. What /sys/bus/cxl/devices/memX/security/erase @@ -92,7 +96,12 @@ Contact: linux-cxl@vger.kernel.org Description: (WO) Write a boolean 'true' string value to this attribute to secure erase user data by changing the media encryption keys for - all user data areas of the device. + all user data areas of the device. This functionality requires + the device to be disabled, that is, not actively decoding any + HPA ranges. This permits avoiding explicit global CPU cache + management, relying instead for it to be done when a region + transitions between software programmed and hardware committed + states. What: /sys/bus/cxl/devices/memX/firmware/ -- cgit v1.2.3 From 3de8cd2242419fb0adaee629d488acfd6cd93c92 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 25 Jul 2023 22:19:39 -0700 Subject: cxl/memdev: Document security state in kern-doc ... as is the case with all members of struct cxl_memdev_state. Signed-off-by: Davidlohr Bueso Link: https://lore.kernel.org/r/20230726051940.3570-3-dave@stgolabs.net Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- drivers/cxl/cxlmem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 499113328586..f3aca828fbec 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -434,6 +434,7 @@ struct cxl_dev_state { * @next_persistent_bytes: persistent capacity change pending device reset * @event: event log driver state * @poison: poison driver state info + * @security: security driver state info * @fw: firmware upload / activation state * @mbox_send: @dev specific transport for transmitting mailbox commands * -- cgit v1.2.3 From ad64f5952ce3ea565c7f76ec37ab41df0dde773a Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 25 Jul 2023 22:19:40 -0700 Subject: cxl/memdev: Only show sanitize sysfs files when supported If the device does not support Sanitize or Secure Erase commands, hide the respective sysfs interfaces such that the operation can never be attempted. In order to be generic, keep track of the enabled security commands found in the CEL - the driver does not support Security Passthrough. Signed-off-by: Davidlohr Bueso Link: https://lore.kernel.org/r/20230726051940.3570-4-dave@stgolabs.net Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- Documentation/ABI/testing/sysfs-bus-cxl | 6 +++-- drivers/cxl/core/mbox.c | 45 ++++++++++++++++++++++++++++++++- drivers/cxl/core/memdev.c | 19 ++++++++++++++ drivers/cxl/cxlmem.h | 15 +++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index c4c4acb1f3b3..087f762ebfd5 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -86,7 +86,8 @@ Description: HPA ranges. This permits avoiding explicit global CPU cache management, relying instead for it to be done when a region transitions between software programmed and hardware committed - states. + states. If this file is not present, then there is no hardware + support for the operation. What /sys/bus/cxl/devices/memX/security/erase @@ -101,7 +102,8 @@ Description: HPA ranges. This permits avoiding explicit global CPU cache management, relying instead for it to be done when a region transitions between software programmed and hardware committed - states. + states. If this file is not present, then there is no hardware + support for the operation. What: /sys/bus/cxl/devices/memX/firmware/ diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index d6d067fbee97..ca60bb8114f2 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -121,6 +121,45 @@ static bool cxl_is_security_command(u16 opcode) return false; } +static void cxl_set_security_cmd_enabled(struct cxl_security_state *security, + u16 opcode) +{ + switch (opcode) { + case CXL_MBOX_OP_SANITIZE: + set_bit(CXL_SEC_ENABLED_SANITIZE, security->enabled_cmds); + break; + case CXL_MBOX_OP_SECURE_ERASE: + set_bit(CXL_SEC_ENABLED_SECURE_ERASE, + security->enabled_cmds); + break; + case CXL_MBOX_OP_GET_SECURITY_STATE: + set_bit(CXL_SEC_ENABLED_GET_SECURITY_STATE, + security->enabled_cmds); + break; + case CXL_MBOX_OP_SET_PASSPHRASE: + set_bit(CXL_SEC_ENABLED_SET_PASSPHRASE, + security->enabled_cmds); + break; + case CXL_MBOX_OP_DISABLE_PASSPHRASE: + set_bit(CXL_SEC_ENABLED_DISABLE_PASSPHRASE, + security->enabled_cmds); + break; + case CXL_MBOX_OP_UNLOCK: + set_bit(CXL_SEC_ENABLED_UNLOCK, security->enabled_cmds); + break; + case CXL_MBOX_OP_FREEZE_SECURITY: + set_bit(CXL_SEC_ENABLED_FREEZE_SECURITY, + security->enabled_cmds); + break; + case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE: + set_bit(CXL_SEC_ENABLED_PASSPHRASE_SECURE_ERASE, + security->enabled_cmds); + break; + default: + break; + } +} + static bool cxl_is_poison_command(u16 opcode) { #define CXL_MBOX_OP_POISON_CMDS 0x43 @@ -677,7 +716,8 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) u16 opcode = le16_to_cpu(cel_entry[i].opcode); struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); - if (!cmd && !cxl_is_poison_command(opcode)) { + if (!cmd && (!cxl_is_poison_command(opcode) || + !cxl_is_security_command(opcode))) { dev_dbg(dev, "Opcode 0x%04x unsupported by driver\n", opcode); continue; @@ -689,6 +729,9 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) if (cxl_is_poison_command(opcode)) cxl_set_poison_cmd_enabled(&mds->poison, opcode); + if (cxl_is_security_command(opcode)) + cxl_set_security_cmd_enabled(&mds->security, opcode); + dev_dbg(dev, "Opcode 0x%04x enabled\n", opcode); } } diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index f99e7ec3cc40..14b547c07f54 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -477,9 +477,28 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = { .attrs = cxl_memdev_pmem_attributes, }; +static umode_t cxl_memdev_security_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + if (a == &dev_attr_security_sanitize.attr && + !test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds)) + return 0; + + if (a == &dev_attr_security_erase.attr && + !test_bit(CXL_SEC_ENABLED_SECURE_ERASE, mds->security.enabled_cmds)) + return 0; + + return a->mode; +} + static struct attribute_group cxl_memdev_security_attribute_group = { .name = "security", .attrs = cxl_memdev_security_attributes, + .is_visible = cxl_memdev_security_visible, }; static const struct attribute_group *cxl_memdev_attribute_groups[] = { diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index f3aca828fbec..706f8a6d1ef4 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -244,6 +244,19 @@ enum poison_cmd_enabled_bits { CXL_POISON_ENABLED_MAX }; +/* Device enabled security commands */ +enum security_cmd_enabled_bits { + CXL_SEC_ENABLED_SANITIZE, + CXL_SEC_ENABLED_SECURE_ERASE, + CXL_SEC_ENABLED_GET_SECURITY_STATE, + CXL_SEC_ENABLED_SET_PASSPHRASE, + CXL_SEC_ENABLED_DISABLE_PASSPHRASE, + CXL_SEC_ENABLED_UNLOCK, + CXL_SEC_ENABLED_FREEZE_SECURITY, + CXL_SEC_ENABLED_PASSPHRASE_SECURE_ERASE, + CXL_SEC_ENABLED_MAX +}; + /** * struct cxl_poison_state - Driver poison state info * @@ -346,6 +359,7 @@ struct cxl_fw_state { * struct cxl_security_state - Device security state * * @state: state of last security operation + * @enabled_cmds: All security commands enabled in the CEL * @poll: polling for sanitization is enabled, device has no mbox irq support * @poll_tmo_secs: polling timeout * @poll_dwork: polling work item @@ -353,6 +367,7 @@ struct cxl_fw_state { */ struct cxl_security_state { unsigned long state; + DECLARE_BITMAP(enabled_cmds, CXL_SEC_ENABLED_MAX); bool poll; int poll_tmo_secs; struct delayed_work poll_dwork; -- cgit v1.2.3 From e68409db995380d1badacba41ff24996bd396171 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 26 Jul 2023 09:51:51 -0400 Subject: net: sched: cls_u32: Fix match key mis-addressing A match entry is uniquely identified with an "address" or "path" in the form of: hashtable ID(12b):bucketid(8b):nodeid(12b). When creating table match entries all of hash table id, bucket id and node (match entry id) are needed to be either specified by the user or reasonable in-kernel defaults are used. The in-kernel default for a table id is 0x800(omnipresent root table); for bucketid it is 0x0. Prior to this fix there was none for a nodeid i.e. the code assumed that the user passed the correct nodeid and if the user passes a nodeid of 0 (as Mingi Cho did) then that is what was used. But nodeid of 0 is reserved for identifying the table. This is not a problem until we dump. The dump code notices that the nodeid is zero and assumes it is referencing a table and therefore references table struct tc_u_hnode instead of what was created i.e match entry struct tc_u_knode. Ming does an equivalent of: tc filter add dev dummy0 parent 10: prio 1 handle 0x1000 \ protocol ip u32 match ip src 10.0.0.1/32 classid 10:1 action ok Essentially specifying a table id 0, bucketid 1 and nodeid of zero Tableid 0 is remapped to the default of 0x800. Bucketid 1 is ignored and defaults to 0x00. Nodeid was assumed to be what Ming passed - 0x000 dumping before fix shows: ~$ tc filter ls dev dummy0 parent 10: filter protocol ip pref 1 u32 chain 0 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor -30591 Note that the last line reports a table instead of a match entry (you can tell this because it says "ht divisor..."). As a result of reporting the wrong data type (misinterpretting of struct tc_u_knode as being struct tc_u_hnode) the divisor is reported with value of -30591. Ming identified this as part of the heap address (physmap_base is 0xffff8880 (-30591 - 1)). The fix is to ensure that when table entry matches are added and no nodeid is specified (i.e nodeid == 0) then we get the next available nodeid from the table's pool. After the fix, this is what the dump shows: $ tc filter ls dev dummy0 parent 10: filter protocol ip pref 1 u32 chain 0 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1 filter protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 10:1 not_in_hw match 0a000001/ffffffff at 12 action order 1: gact action pass random type none pass val 0 index 1 ref 1 bind 1 Reported-by: Mingi Cho Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20230726135151.416917-1-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/cls_u32.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 5abf31e432ca..907e58841fe8 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -1024,18 +1024,62 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return -EINVAL; } + /* At this point, we need to derive the new handle that will be used to + * uniquely map the identity of this table match entry. The + * identity of the entry that we need to construct is 32 bits made of: + * htid(12b):bucketid(8b):node/entryid(12b) + * + * At this point _we have the table(ht)_ in which we will insert this + * entry. We carry the table's id in variable "htid". + * Note that earlier code picked the ht selection either by a) the user + * providing the htid specified via TCA_U32_HASH attribute or b) when + * no such attribute is passed then the root ht, is default to at ID + * 0x[800][00][000]. Rule: the root table has a single bucket with ID 0. + * If OTOH the user passed us the htid, they may also pass a bucketid of + * choice. 0 is fine. For example a user htid is 0x[600][01][000] it is + * indicating hash bucketid of 1. Rule: the entry/node ID _cannot_ be + * passed via the htid, so even if it was non-zero it will be ignored. + * + * We may also have a handle, if the user passed one. The handle also + * carries the same addressing of htid(12b):bucketid(8b):node/entryid(12b). + * Rule: the bucketid on the handle is ignored even if one was passed; + * rather the value on "htid" is always assumed to be the bucketid. + */ if (handle) { + /* Rule: The htid from handle and tableid from htid must match */ if (TC_U32_HTID(handle) && TC_U32_HTID(handle ^ htid)) { NL_SET_ERR_MSG_MOD(extack, "Handle specified hash table address mismatch"); return -EINVAL; } - handle = htid | TC_U32_NODE(handle); - err = idr_alloc_u32(&ht->handle_idr, NULL, &handle, handle, - GFP_KERNEL); - if (err) - return err; - } else + /* Ok, so far we have a valid htid(12b):bucketid(8b) but we + * need to finalize the table entry identification with the last + * part - the node/entryid(12b)). Rule: Nodeid _cannot be 0_ for + * entries. Rule: nodeid of 0 is reserved only for tables(see + * earlier code which processes TC_U32_DIVISOR attribute). + * Rule: The nodeid can only be derived from the handle (and not + * htid). + * Rule: if the handle specified zero for the node id example + * 0x60000000, then pick a new nodeid from the pool of IDs + * this hash table has been allocating from. + * If OTOH it is specified (i.e for example the user passed a + * handle such as 0x60000123), then we use it generate our final + * handle which is used to uniquely identify the match entry. + */ + if (!TC_U32_NODE(handle)) { + handle = gen_new_kid(ht, htid); + } else { + handle = htid | TC_U32_NODE(handle); + err = idr_alloc_u32(&ht->handle_idr, NULL, &handle, + handle, GFP_KERNEL); + if (err) + return err; + } + } else { + /* The user did not give us a handle; lets just generate one + * from the table's pool of nodeids. + */ handle = gen_new_kid(ht, htid); + } if (tb[TCA_U32_SEL] == NULL) { NL_SET_ERR_MSG_MOD(extack, "Selector not specified"); -- cgit v1.2.3 From 56c6be35fcbed54279df0a2c9e60480a61841d6f Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Thu, 27 Jul 2023 08:56:19 +0000 Subject: mISDN: hfcpci: Fix potential deadlock on &hc->lock As &hc->lock is acquired by both timer _hfcpci_softirq() and hardirq hfcpci_int(), the timer should disable irq before lock acquisition otherwise deadlock could happen if the timmer is preemtped by the hadr irq. Possible deadlock scenario: hfcpci_softirq() (timer) -> _hfcpci_softirq() -> spin_lock(&hc->lock); -> hfcpci_int() -> spin_lock(&hc->lock); (deadlock here) This flaw was found by an experimental static analysis tool I am developing for irq-related deadlock. The tentative patch fixes the potential deadlock by spin_lock_irq() in timer. Fixes: b36b654a7e82 ("mISDN: Create /sys/class/mISDN") Signed-off-by: Chengfeng Ye Link: https://lore.kernel.org/r/20230727085619.7419-1-dg573847474@gmail.com Signed-off-by: Jakub Kicinski --- drivers/isdn/hardware/mISDN/hfcpci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index c0331b268010..fe391de1aba3 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -839,7 +839,7 @@ hfcpci_fill_fifo(struct bchannel *bch) *z1t = cpu_to_le16(new_z1); /* now send data */ if (bch->tx_idx < bch->tx_skb->len) return; - dev_kfree_skb(bch->tx_skb); + dev_kfree_skb_any(bch->tx_skb); if (get_next_bframe(bch)) goto next_t_frame; return; @@ -895,7 +895,7 @@ hfcpci_fill_fifo(struct bchannel *bch) } bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ bz->f1 = new_f1; /* next frame */ - dev_kfree_skb(bch->tx_skb); + dev_kfree_skb_any(bch->tx_skb); get_next_bframe(bch); } @@ -1119,7 +1119,7 @@ tx_birq(struct bchannel *bch) if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) hfcpci_fill_fifo(bch); else { - dev_kfree_skb(bch->tx_skb); + dev_kfree_skb_any(bch->tx_skb); if (get_next_bframe(bch)) hfcpci_fill_fifo(bch); } @@ -2277,7 +2277,7 @@ _hfcpci_softirq(struct device *dev, void *unused) return 0; if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { - spin_lock(&hc->lock); + spin_lock_irq(&hc->lock); bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ main_rec_hfcpci(bch); @@ -2288,7 +2288,7 @@ _hfcpci_softirq(struct device *dev, void *unused) main_rec_hfcpci(bch); tx_birq(bch); } - spin_unlock(&hc->lock); + spin_unlock_irq(&hc->lock); } return 0; } -- cgit v1.2.3 From 238353088e9b28d61f58994aa058d736fc306614 Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 25 Jul 2023 11:58:26 +0100 Subject: scripts/kallsyms: Fix build failure by setting errno before calling getline() getline() returns -1 at EOF as well as on error. It also doesn't set errno to 0 on success, so initialize it to 0 before using errno to check for an error condition. See the paragraph here [1]: For some system calls and library functions (e.g., getpriority(2)), -1 is a valid return on success. In such cases, a successful return can be distinguished from an error return by setting errno to zero before the call, and then, if the call returns a status that indicates that an error may have occurred, checking to see if errno has a nonzero value. Bear has a bug [2] that launches processes with errno set and causes the following build failure: $ bear -- make LLVM=1 ... LD .tmp_vmlinux.kallsyms1 NM .tmp_vmlinux.kallsyms1.syms KSYMS .tmp_vmlinux.kallsyms1.S read_symbol: Invalid argument [1]: https://linux.die.net/man/3/errno [2]: https://github.com/rizsotto/Bear/issues/469 Fixes: 1c975da56a6f ("scripts/kallsyms: remove KSYM_NAME_LEN_BUFFER") Reviewed-by: Miguel Ojeda Signed-off-by: James Clark Signed-off-by: Masahiro Yamada --- scripts/kallsyms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 16c87938b316..653b92f6d4c8 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -129,6 +129,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len) ssize_t readlen; struct sym_entry *sym; + errno = 0; readlen = getline(buf, buf_len, in); if (readlen < 0) { if (errno) { -- cgit v1.2.3 From 8a4629055ef55177b5b63dab1ecce676bd8cccdd Mon Sep 17 00:00:00 2001 From: Yiyuan Guo Date: Fri, 30 Jun 2023 22:37:19 +0800 Subject: iio: cros_ec: Fix the allocation size for cros_ec_command The struct cros_ec_command contains several integer fields and a trailing array. An allocation size neglecting the integer fields can lead to buffer overrun. Reviewed-by: Tzung-Bi Shih Signed-off-by: Yiyuan Guo Fixes: 974e6f02e27e ("iio: cros_ec_sensors_core: Add common functions for the ChromeOS EC Sensor Hub.") Link: https://lore.kernel.org/r/20230630143719.1513906-1-yguoaz@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 943e9e14d1e9..b72d39fc2434 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -253,7 +253,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, platform_set_drvdata(pdev, indio_dev); state->ec = ec->ec_dev; - state->msg = devm_kzalloc(&pdev->dev, + state->msg = devm_kzalloc(&pdev->dev, sizeof(*state->msg) + max((u16)sizeof(struct ec_params_motion_sense), state->ec->max_response), GFP_KERNEL); if (!state->msg) -- cgit v1.2.3 From 238ec850b95a02dcdff3edc86781aa913549282f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 28 Jul 2023 17:28:43 -0500 Subject: x86/srso: Fix return thunks in generated code Set X86_FEATURE_RETHUNK when enabling the SRSO mitigation so that generated code (e.g., ftrace, static call, eBPF) generates "jmp __x86_return_thunk" instead of RET. [ bp: Add a comment. ] Fixes: fb3bd914b3ec ("x86/srso: Add a Speculative RAS Overflow mitigation") Signed-off-by: Josh Poimboeuf Signed-off-by: Borislav Petkov (AMD) --- arch/x86/kernel/alternative.c | 4 +--- arch/x86/kernel/cpu/bugs.c | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 920a8ca7a8f8..2dcf3a06af09 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -707,9 +707,7 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes) int i = 0; /* Patch the custom return thunks... */ - if (cpu_feature_enabled(X86_FEATURE_RETHUNK) || - cpu_feature_enabled(X86_FEATURE_SRSO) || - cpu_feature_enabled(X86_FEATURE_SRSO_ALIAS)) { + if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { i = JMP32_INSN_SIZE; __text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i); } else { diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index d4109eb5eb2e..7314a6bdc862 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2297,6 +2297,12 @@ static void __init srso_select_mitigation(void) case SRSO_CMD_SAFE_RET: if (IS_ENABLED(CONFIG_CPU_SRSO)) { + /* + * Enable the return thunk for generated code + * like ftrace, static_call, etc. + */ + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + if (boot_cpu_data.x86 == 0x19) setup_force_cpu_cap(X86_FEATURE_SRSO_ALIAS); else -- cgit v1.2.3 From 0c02cc576eac161601927b41634f80bfd55bfa9e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 27 Jul 2023 20:29:39 +0200 Subject: KVM: s390: fix sthyi error handling Commit 9fb6c9b3fea1 ("s390/sthyi: add cache to store hypervisor info") added cache handling for store hypervisor info. This also changed the possible return code for sthyi_fill(). Instead of only returning a condition code like the sthyi instruction would do, it can now also return a negative error value (-ENOMEM). handle_styhi() was not changed accordingly. In case of an error, the negative error value would incorrectly injected into the guest PSW. Add proper error handling to prevent this, and update the comment which describes the possible return values of sthyi_fill(). Fixes: 9fb6c9b3fea1 ("s390/sthyi: add cache to store hypervisor info") Reviewed-by: Christian Borntraeger Link: https://lore.kernel.org/r/20230727182939.2050744-1-hca@linux.ibm.com Signed-off-by: Heiko Carstens --- arch/s390/kernel/sthyi.c | 6 +++--- arch/s390/kvm/intercept.c | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/s390/kernel/sthyi.c b/arch/s390/kernel/sthyi.c index 4d141e2c132e..2ea7f208f0e7 100644 --- a/arch/s390/kernel/sthyi.c +++ b/arch/s390/kernel/sthyi.c @@ -459,9 +459,9 @@ static int sthyi_update_cache(u64 *rc) * * Fills the destination with system information returned by the STHYI * instruction. The data is generated by emulation or execution of STHYI, - * if available. The return value is the condition code that would be - * returned, the rc parameter is the return code which is passed in - * register R2 + 1. + * if available. The return value is either a negative error value or + * the condition code that would be returned, the rc parameter is the + * return code which is passed in register R2 + 1. */ int sthyi_fill(void *dst, u64 *rc) { diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 954d39adf85c..341abafb96e4 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -389,8 +389,8 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu) */ int handle_sthyi(struct kvm_vcpu *vcpu) { - int reg1, reg2, r = 0; - u64 code, addr, cc = 0, rc = 0; + int reg1, reg2, cc = 0, r = 0; + u64 code, addr, rc = 0; struct sthyi_sctns *sctns = NULL; if (!test_kvm_facility(vcpu->kvm, 74)) @@ -421,7 +421,10 @@ int handle_sthyi(struct kvm_vcpu *vcpu) return -ENOMEM; cc = sthyi_fill(sctns, &rc); - + if (cc < 0) { + free_page((unsigned long)sctns); + return cc; + } out: if (!cc) { if (kvm_s390_pv_cpu_is_protected(vcpu)) { -- cgit v1.2.3 From 3bbbe97ad83db8d9df06daf027b0840188de625d Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Fri, 28 Jul 2023 23:03:22 +0200 Subject: x86/srso: Add a forgotten NOENDBR annotation Fix: vmlinux.o: warning: objtool: .export_symbol+0x29e40: data relocation to !ENDBR: srso_untrain_ret_alias+0x0 Reported-by: Linus Torvalds Signed-off-by: Borislav Petkov (AMD) --- arch/x86/lib/retpoline.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index 845cfb0d748f..2cff585f22f2 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -151,6 +151,7 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) .section .text.__x86.rethunk_untrain SYM_START(srso_untrain_ret_alias, SYM_L_GLOBAL, SYM_A_NONE) + ANNOTATE_NOENDBR ASM_NOP2 lfence jmp __x86_return_thunk -- cgit v1.2.3 From a0b1b2055be34c0ec1371764d040164cde1ead79 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 26 Jul 2023 18:32:00 +0200 Subject: net: stmmac: tegra: Properly allocate clock bulk data The clock data is an array of struct clk_bulk_data, so make sure to allocate enough memory. Fixes: d8ca113724e7 ("net: stmmac: tegra: Add MGBE support") Signed-off-by: Thierry Reding Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c index f8367c5b490b..fbb0ccf84afc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c @@ -234,7 +234,8 @@ static int tegra_mgbe_probe(struct platform_device *pdev) res.addr = mgbe->regs; res.irq = irq; - mgbe->clks = devm_kzalloc(&pdev->dev, sizeof(*mgbe->clks), GFP_KERNEL); + mgbe->clks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(mgbe_clks), + sizeof(*mgbe->clks), GFP_KERNEL); if (!mgbe->clks) return -ENOMEM; -- cgit v1.2.3 From 8d7ae22ae9f8c8a4407f8e993df64440bdbd0cee Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 27 Jul 2023 10:13:42 +0200 Subject: net: dsa: microchip: KSZ9477 register regmap alignment to 32 bit boundaries The commit (SHA1: 5c844d57aa7894154e49cf2fc648bfe2f1aefc1c) provided code to apply "Module 6: Certain PHY registers must be written as pairs instead of singly" errata for KSZ9477 as this chip for certain PHY registers (0xN120 to 0xN13F, N=1,2,3,4,5) must be accesses as 32 bit words instead of 16 or 8 bit access. Otherwise, adjacent registers (no matter if reserved or not) are overwritten with 0x0. Without this patch some registers (e.g. 0x113c or 0x1134) required for 32 bit access are out of valid regmap ranges. As a result, following error is observed and KSZ9477 is not properly configured: ksz-switch spi1.0: can't rmw 32bit reg 0x113c: -EIO ksz-switch spi1.0: can't rmw 32bit reg 0x1134: -EIO ksz-switch spi1.0 lan1 (uninitialized): failed to connect to PHY: -EIO ksz-switch spi1.0 lan1 (uninitialized): error -5 setting up PHY for tree 0, switch 0, port 0 The solution is to modify regmap_reg_range to allow accesses with 4 bytes boundaries. Signed-off-by: Lukasz Majewski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 35 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b18cd170ec06..6c0623f88654 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -635,10 +635,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x1030, 0x1030), regmap_reg_range(0x1100, 0x1115), regmap_reg_range(0x111a, 0x111f), - regmap_reg_range(0x1122, 0x1127), - regmap_reg_range(0x112a, 0x112b), - regmap_reg_range(0x1136, 0x1139), - regmap_reg_range(0x113e, 0x113f), + regmap_reg_range(0x1120, 0x112b), + regmap_reg_range(0x1134, 0x113b), + regmap_reg_range(0x113c, 0x113f), regmap_reg_range(0x1400, 0x1401), regmap_reg_range(0x1403, 0x1403), regmap_reg_range(0x1410, 0x1417), @@ -669,10 +668,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x2030, 0x2030), regmap_reg_range(0x2100, 0x2115), regmap_reg_range(0x211a, 0x211f), - regmap_reg_range(0x2122, 0x2127), - regmap_reg_range(0x212a, 0x212b), - regmap_reg_range(0x2136, 0x2139), - regmap_reg_range(0x213e, 0x213f), + regmap_reg_range(0x2120, 0x212b), + regmap_reg_range(0x2134, 0x213b), + regmap_reg_range(0x213c, 0x213f), regmap_reg_range(0x2400, 0x2401), regmap_reg_range(0x2403, 0x2403), regmap_reg_range(0x2410, 0x2417), @@ -703,10 +701,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x3030, 0x3030), regmap_reg_range(0x3100, 0x3115), regmap_reg_range(0x311a, 0x311f), - regmap_reg_range(0x3122, 0x3127), - regmap_reg_range(0x312a, 0x312b), - regmap_reg_range(0x3136, 0x3139), - regmap_reg_range(0x313e, 0x313f), + regmap_reg_range(0x3120, 0x312b), + regmap_reg_range(0x3134, 0x313b), + regmap_reg_range(0x313c, 0x313f), regmap_reg_range(0x3400, 0x3401), regmap_reg_range(0x3403, 0x3403), regmap_reg_range(0x3410, 0x3417), @@ -737,10 +734,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x4030, 0x4030), regmap_reg_range(0x4100, 0x4115), regmap_reg_range(0x411a, 0x411f), - regmap_reg_range(0x4122, 0x4127), - regmap_reg_range(0x412a, 0x412b), - regmap_reg_range(0x4136, 0x4139), - regmap_reg_range(0x413e, 0x413f), + regmap_reg_range(0x4120, 0x412b), + regmap_reg_range(0x4134, 0x413b), + regmap_reg_range(0x413c, 0x413f), regmap_reg_range(0x4400, 0x4401), regmap_reg_range(0x4403, 0x4403), regmap_reg_range(0x4410, 0x4417), @@ -771,10 +767,9 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x5030, 0x5030), regmap_reg_range(0x5100, 0x5115), regmap_reg_range(0x511a, 0x511f), - regmap_reg_range(0x5122, 0x5127), - regmap_reg_range(0x512a, 0x512b), - regmap_reg_range(0x5136, 0x5139), - regmap_reg_range(0x513e, 0x513f), + regmap_reg_range(0x5120, 0x512b), + regmap_reg_range(0x5134, 0x513b), + regmap_reg_range(0x513c, 0x513f), regmap_reg_range(0x5400, 0x5401), regmap_reg_range(0x5403, 0x5403), regmap_reg_range(0x5410, 0x5417), -- cgit v1.2.3 From e346e231b42bcae6822a6326acfb7b741e9e6026 Mon Sep 17 00:00:00 2001 From: Konstantin Khorenko Date: Thu, 27 Jul 2023 18:26:09 +0300 Subject: qed: Fix scheduling in a tasklet while getting stats Here we've got to a situation when tasklet called usleep_range() in PTT acquire logic, thus welcome to the "scheduling while atomic" BUG(). BUG: scheduling while atomic: swapper/24/0/0x00000100 [] schedule+0x29/0x70 [] schedule_hrtimeout_range_clock+0xb2/0x150 [] schedule_hrtimeout_range+0x13/0x20 [] usleep_range+0x4f/0x70 [] qed_ptt_acquire+0x38/0x100 [qed] [] _qed_get_vport_stats+0x458/0x580 [qed] [] qed_get_vport_stats+0x1c/0xd0 [qed] [] qed_get_protocol_stats+0x93/0x100 [qed] qed_mcp_send_protocol_stats case MFW_DRV_MSG_GET_LAN_STATS: case MFW_DRV_MSG_GET_FCOE_STATS: case MFW_DRV_MSG_GET_ISCSI_STATS: case MFW_DRV_MSG_GET_RDMA_STATS: [] qed_mcp_handle_events+0x2d8/0x890 [qed] qed_int_assertion qed_int_attentions [] qed_int_sp_dpc+0xa50/0xdc0 [qed] [] tasklet_action+0x83/0x140 [] __do_softirq+0x125/0x2bb [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x105/0x110 [] do_IRQ+0x56/0xf0 Fix this by making caller to provide the context whether it could be in atomic context flow or not when getting stats from QED driver. QED driver based on the context provided decide to schedule out or not when acquiring the PTT BAR window. We faced the BUG_ON() while getting vport stats, but according to the code same issue could happen for fcoe and iscsi statistics as well, so fixing them too. Fixes: 6c75424612a7 ("qed: Add support for NCSI statistics.") Fixes: 1e128c81290a ("qed: Add support for hardware offloaded FCoE.") Fixes: 2f2b2614e893 ("qed: Provide iSCSI statistics to management") Cc: Sudarsana Kalluru Cc: David Miller Cc: Manish Chopra Signed-off-by: Konstantin Khorenko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 16 ++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 19 ++++++++++++++----- drivers/net/ethernet/qlogic/qed/qed_fcoe.h | 17 +++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_hw.c | 26 ++++++++++++++++++++++---- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 19 ++++++++++++++----- drivers/net/ethernet/qlogic/qed/qed_iscsi.h | 8 ++++++-- drivers/net/ethernet/qlogic/qed/qed_l2.c | 19 ++++++++++++++----- drivers/net/ethernet/qlogic/qed/qed_l2.h | 24 ++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_main.c | 6 +++--- 9 files changed, 128 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index f8682356d0cf..94d4f9413ab7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -193,6 +193,22 @@ void qed_hw_remove(struct qed_dev *cdev); */ struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn); +/** + * qed_ptt_acquire_context(): Allocate a PTT window honoring the context + * atomicy. + * + * @p_hwfn: HW device data. + * @is_atomic: Hint from the caller - if the func can sleep or not. + * + * Context: The function should not sleep in case is_atomic == true. + * Return: struct qed_ptt. + * + * Should be called at the entry point to the driver + * (at the beginning of an exported function). + */ +struct qed_ptt *qed_ptt_acquire_context(struct qed_hwfn *p_hwfn, + bool is_atomic); + /** * qed_ptt_release(): Release PTT Window. * diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index 3764190b948e..04602ac94708 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -693,13 +693,14 @@ static void _qed_fcoe_get_pstats(struct qed_hwfn *p_hwfn, } static int qed_fcoe_get_stats(struct qed_hwfn *p_hwfn, - struct qed_fcoe_stats *p_stats) + struct qed_fcoe_stats *p_stats, + bool is_atomic) { struct qed_ptt *p_ptt; memset(p_stats, 0, sizeof(*p_stats)); - p_ptt = qed_ptt_acquire(p_hwfn); + p_ptt = qed_ptt_acquire_context(p_hwfn, is_atomic); if (!p_ptt) { DP_ERR(p_hwfn, "Failed to acquire ptt\n"); @@ -973,19 +974,27 @@ static int qed_fcoe_destroy_conn(struct qed_dev *cdev, QED_SPQ_MODE_EBLOCK, NULL); } +static int qed_fcoe_stats_context(struct qed_dev *cdev, + struct qed_fcoe_stats *stats, + bool is_atomic) +{ + return qed_fcoe_get_stats(QED_AFFIN_HWFN(cdev), stats, is_atomic); +} + static int qed_fcoe_stats(struct qed_dev *cdev, struct qed_fcoe_stats *stats) { - return qed_fcoe_get_stats(QED_AFFIN_HWFN(cdev), stats); + return qed_fcoe_stats_context(cdev, stats, false); } void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, - struct qed_mcp_fcoe_stats *stats) + struct qed_mcp_fcoe_stats *stats, + bool is_atomic) { struct qed_fcoe_stats proto_stats; /* Retrieve FW statistics */ memset(&proto_stats, 0, sizeof(proto_stats)); - if (qed_fcoe_stats(cdev, &proto_stats)) { + if (qed_fcoe_stats_context(cdev, &proto_stats, is_atomic)) { DP_VERBOSE(cdev, QED_MSG_STORAGE, "Failed to collect FCoE statistics\n"); return; diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h index 19c85adf4ceb..214e8299ecb4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h @@ -28,8 +28,20 @@ int qed_fcoe_alloc(struct qed_hwfn *p_hwfn); void qed_fcoe_setup(struct qed_hwfn *p_hwfn); void qed_fcoe_free(struct qed_hwfn *p_hwfn); +/** + * qed_get_protocol_stats_fcoe(): Fills provided statistics + * struct with statistics. + * + * @cdev: Qed dev pointer. + * @stats: Points to struct that will be filled with statistics. + * @is_atomic: Hint from the caller - if the func can sleep or not. + * + * Context: The function should not sleep in case is_atomic == true. + * Return: Void. + */ void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, - struct qed_mcp_fcoe_stats *stats); + struct qed_mcp_fcoe_stats *stats, + bool is_atomic); #else /* CONFIG_QED_FCOE */ static inline int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { @@ -40,7 +52,8 @@ static inline void qed_fcoe_setup(struct qed_hwfn *p_hwfn) {} static inline void qed_fcoe_free(struct qed_hwfn *p_hwfn) {} static inline void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, - struct qed_mcp_fcoe_stats *stats) + struct qed_mcp_fcoe_stats *stats, + bool is_atomic) { } #endif /* CONFIG_QED_FCOE */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 554f30b0cfd5..6263f847b6b9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -23,7 +23,10 @@ #include "qed_reg_addr.h" #include "qed_sriov.h" -#define QED_BAR_ACQUIRE_TIMEOUT 1000 +#define QED_BAR_ACQUIRE_TIMEOUT_USLEEP_CNT 1000 +#define QED_BAR_ACQUIRE_TIMEOUT_USLEEP 1000 +#define QED_BAR_ACQUIRE_TIMEOUT_UDELAY_CNT 100000 +#define QED_BAR_ACQUIRE_TIMEOUT_UDELAY 10 /* Invalid values */ #define QED_BAR_INVALID_OFFSET (cpu_to_le32(-1)) @@ -84,12 +87,22 @@ void qed_ptt_pool_free(struct qed_hwfn *p_hwfn) } struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn) +{ + return qed_ptt_acquire_context(p_hwfn, false); +} + +struct qed_ptt *qed_ptt_acquire_context(struct qed_hwfn *p_hwfn, bool is_atomic) { struct qed_ptt *p_ptt; - unsigned int i; + unsigned int i, count; + + if (is_atomic) + count = QED_BAR_ACQUIRE_TIMEOUT_UDELAY_CNT; + else + count = QED_BAR_ACQUIRE_TIMEOUT_USLEEP_CNT; /* Take the free PTT from the list */ - for (i = 0; i < QED_BAR_ACQUIRE_TIMEOUT; i++) { + for (i = 0; i < count; i++) { spin_lock_bh(&p_hwfn->p_ptt_pool->lock); if (!list_empty(&p_hwfn->p_ptt_pool->free_list)) { @@ -105,7 +118,12 @@ struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn) } spin_unlock_bh(&p_hwfn->p_ptt_pool->lock); - usleep_range(1000, 2000); + + if (is_atomic) + udelay(QED_BAR_ACQUIRE_TIMEOUT_UDELAY); + else + usleep_range(QED_BAR_ACQUIRE_TIMEOUT_USLEEP, + QED_BAR_ACQUIRE_TIMEOUT_USLEEP * 2); } DP_NOTICE(p_hwfn, "PTT acquire timeout - failed to allocate PTT\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 511ab214eb9c..980e7289b481 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -999,13 +999,14 @@ static void _qed_iscsi_get_pstats(struct qed_hwfn *p_hwfn, } static int qed_iscsi_get_stats(struct qed_hwfn *p_hwfn, - struct qed_iscsi_stats *stats) + struct qed_iscsi_stats *stats, + bool is_atomic) { struct qed_ptt *p_ptt; memset(stats, 0, sizeof(*stats)); - p_ptt = qed_ptt_acquire(p_hwfn); + p_ptt = qed_ptt_acquire_context(p_hwfn, is_atomic); if (!p_ptt) { DP_ERR(p_hwfn, "Failed to acquire ptt\n"); return -EAGAIN; @@ -1336,9 +1337,16 @@ static int qed_iscsi_destroy_conn(struct qed_dev *cdev, QED_SPQ_MODE_EBLOCK, NULL); } +static int qed_iscsi_stats_context(struct qed_dev *cdev, + struct qed_iscsi_stats *stats, + bool is_atomic) +{ + return qed_iscsi_get_stats(QED_AFFIN_HWFN(cdev), stats, is_atomic); +} + static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats) { - return qed_iscsi_get_stats(QED_AFFIN_HWFN(cdev), stats); + return qed_iscsi_stats_context(cdev, stats, false); } static int qed_iscsi_change_mac(struct qed_dev *cdev, @@ -1358,13 +1366,14 @@ static int qed_iscsi_change_mac(struct qed_dev *cdev, } void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, - struct qed_mcp_iscsi_stats *stats) + struct qed_mcp_iscsi_stats *stats, + bool is_atomic) { struct qed_iscsi_stats proto_stats; /* Retrieve FW statistics */ memset(&proto_stats, 0, sizeof(proto_stats)); - if (qed_iscsi_stats(cdev, &proto_stats)) { + if (qed_iscsi_stats_context(cdev, &proto_stats, is_atomic)) { DP_VERBOSE(cdev, QED_MSG_STORAGE, "Failed to collect ISCSI statistics\n"); return; diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h index dec2b00259d4..974cb8d26608 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h @@ -39,11 +39,14 @@ void qed_iscsi_free(struct qed_hwfn *p_hwfn); * * @cdev: Qed dev pointer. * @stats: Points to struct that will be filled with statistics. + * @is_atomic: Hint from the caller - if the func can sleep or not. * + * Context: The function should not sleep in case is_atomic == true. * Return: Void. */ void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, - struct qed_mcp_iscsi_stats *stats); + struct qed_mcp_iscsi_stats *stats, + bool is_atomic); #else /* IS_ENABLED(CONFIG_QED_ISCSI) */ static inline int qed_iscsi_alloc(struct qed_hwfn *p_hwfn) { @@ -56,7 +59,8 @@ static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn) {} static inline void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, - struct qed_mcp_iscsi_stats *stats) {} + struct qed_mcp_iscsi_stats *stats, + bool is_atomic) {} #endif /* IS_ENABLED(CONFIG_QED_ISCSI) */ #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 7776d3bdd459..970b9aabbc3d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -1863,7 +1863,8 @@ static void __qed_get_vport_stats(struct qed_hwfn *p_hwfn, } static void _qed_get_vport_stats(struct qed_dev *cdev, - struct qed_eth_stats *stats) + struct qed_eth_stats *stats, + bool is_atomic) { u8 fw_vport = 0; int i; @@ -1872,10 +1873,11 @@ static void _qed_get_vport_stats(struct qed_dev *cdev, for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; - struct qed_ptt *p_ptt = IS_PF(cdev) ? qed_ptt_acquire(p_hwfn) - : NULL; + struct qed_ptt *p_ptt; bool b_get_port_stats; + p_ptt = IS_PF(cdev) ? qed_ptt_acquire_context(p_hwfn, is_atomic) + : NULL; if (IS_PF(cdev)) { /* The main vport index is relative first */ if (qed_fw_vport(p_hwfn, 0, &fw_vport)) { @@ -1900,6 +1902,13 @@ out: } void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats) +{ + qed_get_vport_stats_context(cdev, stats, false); +} + +void qed_get_vport_stats_context(struct qed_dev *cdev, + struct qed_eth_stats *stats, + bool is_atomic) { u32 i; @@ -1908,7 +1917,7 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats) return; } - _qed_get_vport_stats(cdev, stats); + _qed_get_vport_stats(cdev, stats, is_atomic); if (!cdev->reset_stats) return; @@ -1960,7 +1969,7 @@ void qed_reset_vport_stats(struct qed_dev *cdev) if (!cdev->reset_stats) { DP_INFO(cdev, "Reset stats not allocated\n"); } else { - _qed_get_vport_stats(cdev, cdev->reset_stats); + _qed_get_vport_stats(cdev, cdev->reset_stats, false); cdev->reset_stats->common.link_change_count = 0; } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index a538cf478c14..2d2f82c785ad 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -249,8 +249,32 @@ qed_sp_eth_rx_queues_update(struct qed_hwfn *p_hwfn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data); +/** + * qed_get_vport_stats(): Fills provided statistics + * struct with statistics. + * + * @cdev: Qed dev pointer. + * @stats: Points to struct that will be filled with statistics. + * + * Return: Void. + */ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats); +/** + * qed_get_vport_stats_context(): Fills provided statistics + * struct with statistics. + * + * @cdev: Qed dev pointer. + * @stats: Points to struct that will be filled with statistics. + * @is_atomic: Hint from the caller - if the func can sleep or not. + * + * Context: The function should not sleep in case is_atomic == true. + * Return: Void. + */ +void qed_get_vport_stats_context(struct qed_dev *cdev, + struct qed_eth_stats *stats, + bool is_atomic); + void qed_reset_vport_stats(struct qed_dev *cdev); /** diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index f5af83342856..c278f8893042 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -3092,7 +3092,7 @@ void qed_get_protocol_stats(struct qed_dev *cdev, switch (type) { case QED_MCP_LAN_STATS: - qed_get_vport_stats(cdev, ð_stats); + qed_get_vport_stats_context(cdev, ð_stats, true); stats->lan_stats.ucast_rx_pkts = eth_stats.common.rx_ucast_pkts; stats->lan_stats.ucast_tx_pkts = @@ -3100,10 +3100,10 @@ void qed_get_protocol_stats(struct qed_dev *cdev, stats->lan_stats.fcs_err = -1; break; case QED_MCP_FCOE_STATS: - qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); + qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats, true); break; case QED_MCP_ISCSI_STATS: - qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); + qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats, true); break; default: DP_VERBOSE(cdev, QED_MSG_SP, -- cgit v1.2.3 From 7938cd15436873f649f31cb867bac2d88ca564d0 Mon Sep 17 00:00:00 2001 From: Richard Gobert Date: Thu, 27 Jul 2023 17:33:56 +0200 Subject: net: gro: fix misuse of CB in udp socket lookup This patch fixes a misuse of IP{6}CB(skb) in GRO, while calling to `udp6_lib_lookup2` when handling udp tunnels. `udp6_lib_lookup2` fetch the device from CB. The fix changes it to fetch the device from `skb->dev`. l3mdev case requires special attention since it has a master and a slave device. Fixes: a6024562ffd7 ("udp: Add GRO functions to UDP socket") Reported-by: Gal Pressman Signed-off-by: Richard Gobert Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/gro.h | 43 +++++++++++++++++++++++++++++++++++++++++++ net/ipv4/udp.c | 8 ++++++-- net/ipv4/udp_offload.c | 7 +++++-- net/ipv6/udp.c | 8 ++++++-- net/ipv6/udp_offload.c | 7 +++++-- 5 files changed, 65 insertions(+), 8 deletions(-) diff --git a/include/net/gro.h b/include/net/gro.h index 75efa6fb8441..88644b3ca660 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -452,6 +452,49 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb, gro_normal_list(napi); } +/* This function is the alternative of 'inet_iif' and 'inet_sdif' + * functions in case we can not rely on fields of IPCB. + * + * The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized. + * The caller must hold the RCU read lock. + */ +static inline void inet_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif) +{ + *iif = inet_iif(skb) ?: skb->dev->ifindex; + *sdif = 0; + +#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) + if (netif_is_l3_slave(skb->dev)) { + struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev); + + *sdif = *iif; + *iif = master ? master->ifindex : 0; + } +#endif +} + +/* This function is the alternative of 'inet6_iif' and 'inet6_sdif' + * functions in case we can not rely on fields of IP6CB. + * + * The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized. + * The caller must hold the RCU read lock. + */ +static inline void inet6_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif) +{ + /* using skb->dev->ifindex because skb_dst(skb) is not initialized */ + *iif = skb->dev->ifindex; + *sdif = 0; + +#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) + if (netif_is_l3_slave(skb->dev)) { + struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev); + + *sdif = *iif; + *iif = master ? master->ifindex : 0; + } +#endif +} + extern struct list_head offload_base; #endif /* _NET_IPV6_GRO_H */ diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 42a96b3547c9..abfa860367aa 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -114,6 +114,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_IPV6) #include #endif @@ -555,10 +556,13 @@ struct sock *udp4_lib_lookup_skb(const struct sk_buff *skb, { const struct iphdr *iph = ip_hdr(skb); struct net *net = dev_net(skb->dev); + int iif, sdif; + + inet_get_iif_sdif(skb, &iif, &sdif); return __udp4_lib_lookup(net, iph->saddr, sport, - iph->daddr, dport, inet_iif(skb), - inet_sdif(skb), net->ipv4.udp_table, NULL); + iph->daddr, dport, iif, + sdif, net->ipv4.udp_table, NULL); } /* Must be called under rcu_read_lock(). diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index f402946da344..0f46b3c2e4ac 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -609,10 +609,13 @@ static struct sock *udp4_gro_lookup_skb(struct sk_buff *skb, __be16 sport, { const struct iphdr *iph = skb_gro_network_header(skb); struct net *net = dev_net(skb->dev); + int iif, sdif; + + inet_get_iif_sdif(skb, &iif, &sdif); return __udp4_lib_lookup(net, iph->saddr, sport, - iph->daddr, dport, inet_iif(skb), - inet_sdif(skb), net->ipv4.udp_table, NULL); + iph->daddr, dport, iif, + sdif, net->ipv4.udp_table, NULL); } INDIRECT_CALLABLE_SCOPE diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b7c972aa09a7..e5da5d1cb215 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -300,10 +301,13 @@ struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb, { const struct ipv6hdr *iph = ipv6_hdr(skb); struct net *net = dev_net(skb->dev); + int iif, sdif; + + inet6_get_iif_sdif(skb, &iif, &sdif); return __udp6_lib_lookup(net, &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - inet6_sdif(skb), net->ipv4.udp_table, NULL); + &iph->daddr, dport, iif, + sdif, net->ipv4.udp_table, NULL); } /* Must be called under rcu_read_lock(). diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 09fa7a42cb93..6b95ba241ebe 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -118,10 +118,13 @@ static struct sock *udp6_gro_lookup_skb(struct sk_buff *skb, __be16 sport, { const struct ipv6hdr *iph = skb_gro_network_header(skb); struct net *net = dev_net(skb->dev); + int iif, sdif; + + inet6_get_iif_sdif(skb, &iif, &sdif); return __udp6_lib_lookup(net, &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - inet6_sdif(skb), net->ipv4.udp_table, NULL); + &iph->daddr, dport, iif, + sdif, net->ipv4.udp_table, NULL); } INDIRECT_CALLABLE_SCOPE -- cgit v1.2.3 From fe11fdcb4207907d80cda2e73777465d68131e66 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:08 +0000 Subject: net: annotate data-races around sk->sk_reserved_mem sk_getsockopt() runs locklessly. This means sk->sk_reserved_mem can be read while other threads are changing its value. Add missing annotations where they are needed. Fixes: 2bb2f5fb21b0 ("net: add new socket option SO_RESERVE_MEM") Signed-off-by: Eric Dumazet Cc: Wei Wang Signed-off-by: David S. Miller --- net/core/sock.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 9370fd50aa2c..bd201d15e72a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1007,7 +1007,7 @@ static void sock_release_reserved_memory(struct sock *sk, int bytes) bytes = round_down(bytes, PAGE_SIZE); WARN_ON(bytes > sk->sk_reserved_mem); - sk->sk_reserved_mem -= bytes; + WRITE_ONCE(sk->sk_reserved_mem, sk->sk_reserved_mem - bytes); sk_mem_reclaim(sk); } @@ -1044,7 +1044,8 @@ static int sock_reserve_memory(struct sock *sk, int bytes) } sk->sk_forward_alloc += pages << PAGE_SHIFT; - sk->sk_reserved_mem += pages << PAGE_SHIFT; + WRITE_ONCE(sk->sk_reserved_mem, + sk->sk_reserved_mem + (pages << PAGE_SHIFT)); return 0; } @@ -1973,7 +1974,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_RESERVE_MEM: - v.val = sk->sk_reserved_mem; + v.val = READ_ONCE(sk->sk_reserved_mem); break; case SO_TXREHASH: -- cgit v1.2.3 From c76a0328899bbe226f8adeb88b8da9e4167bd316 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:09 +0000 Subject: net: annotate data-race around sk->sk_txrehash sk_getsockopt() runs locklessly. This means sk->sk_txrehash can be read while other threads are changing its value. Other locations were handled in commit cb6cd2cec799 ("tcp: Change SYN ACK retransmit behaviour to account for rehash") Fixes: 26859240e4ee ("txhash: Add socket option to control TX hash rethink behavior") Signed-off-by: Eric Dumazet Cc: Akhmat Karakotov Signed-off-by: David S. Miller --- net/core/sock.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index bd201d15e72a..adec93dda56a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1534,7 +1534,9 @@ set_sndbuf: } if ((u8)val == SOCK_TXREHASH_DEFAULT) val = READ_ONCE(sock_net(sk)->core.sysctl_txrehash); - /* Paired with READ_ONCE() in tcp_rtx_synack() */ + /* Paired with READ_ONCE() in tcp_rtx_synack() + * and sk_getsockopt(). + */ WRITE_ONCE(sk->sk_txrehash, (u8)val); break; @@ -1978,7 +1980,8 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_TXREHASH: - v.val = sk->sk_txrehash; + /* Paired with WRITE_ONCE() in sk_setsockopt() */ + v.val = READ_ONCE(sk->sk_txrehash); break; default: -- cgit v1.2.3 From ea7f45ef77b39e72244d282e47f6cb1ef4135cd2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:10 +0000 Subject: net: annotate data-races around sk->sk_max_pacing_rate sk_getsockopt() runs locklessly. This means sk->sk_max_pacing_rate can be read while other threads are changing its value. Fixes: 62748f32d501 ("net: introduce SO_MAX_PACING_RATE") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index adec93dda56a..fec18755f772 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1439,7 +1439,8 @@ set_sndbuf: cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); - sk->sk_max_pacing_rate = ulval; + /* Pairs with READ_ONCE() from sk_getsockopt() */ + WRITE_ONCE(sk->sk_max_pacing_rate, ulval); sk->sk_pacing_rate = min(sk->sk_pacing_rate, ulval); break; } @@ -1903,12 +1904,14 @@ int sk_getsockopt(struct sock *sk, int level, int optname, #endif case SO_MAX_PACING_RATE: + /* The READ_ONCE() pair with the WRITE_ONCE() in sk_setsockopt() */ if (sizeof(v.ulval) != sizeof(v.val) && len >= sizeof(v.ulval)) { lv = sizeof(v.ulval); - v.ulval = sk->sk_max_pacing_rate; + v.ulval = READ_ONCE(sk->sk_max_pacing_rate); } else { /* 32bit version */ - v.val = min_t(unsigned long, sk->sk_max_pacing_rate, ~0U); + v.val = min_t(unsigned long, ~0U, + READ_ONCE(sk->sk_max_pacing_rate)); } break; -- cgit v1.2.3 From e6d12bdb435d23ff6c1890c852d85408a2f496ee Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:11 +0000 Subject: net: add missing READ_ONCE(sk->sk_rcvlowat) annotation In a prior commit, I forgot to change sk_getsockopt() when reading sk->sk_rcvlowat locklessly. Fixes: eac66402d1c3 ("net: annotate sk->sk_rcvlowat lockless reads") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index fec18755f772..08e605001605 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1730,7 +1730,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_RCVLOWAT: - v.val = sk->sk_rcvlowat; + v.val = READ_ONCE(sk->sk_rcvlowat); break; case SO_SNDLOWAT: -- cgit v1.2.3 From 285975dd674258ccb33e77a1803e8f2015e67105 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:12 +0000 Subject: net: annotate data-races around sk->sk_{rcv|snd}timeo sk_getsockopt() runs without locks, we must add annotations to sk->sk_rcvtimeo and sk->sk_sndtimeo. In the future we might allow fetching these fields before we lock the socket in TCP fast path. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 24 ++++++++++++++---------- net/sched/em_meta.c | 4 ++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 08e605001605..264c99c190ac 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -429,6 +429,7 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, { struct __kernel_sock_timeval tv; int err = sock_copy_user_timeval(&tv, optval, optlen, old_timeval); + long val; if (err) return err; @@ -439,7 +440,7 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, if (tv.tv_sec < 0) { static int warned __read_mostly; - *timeo_p = 0; + WRITE_ONCE(*timeo_p, 0); if (warned < 10 && net_ratelimit()) { warned++; pr_info("%s: `%s' (pid %d) tries to set negative timeout\n", @@ -447,11 +448,12 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, } return 0; } - *timeo_p = MAX_SCHEDULE_TIMEOUT; - if (tv.tv_sec == 0 && tv.tv_usec == 0) - return 0; - if (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) - *timeo_p = tv.tv_sec * HZ + DIV_ROUND_UP((unsigned long)tv.tv_usec, USEC_PER_SEC / HZ); + val = MAX_SCHEDULE_TIMEOUT; + if ((tv.tv_sec || tv.tv_usec) && + (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1))) + val = tv.tv_sec * HZ + DIV_ROUND_UP((unsigned long)tv.tv_usec, + USEC_PER_SEC / HZ); + WRITE_ONCE(*timeo_p, val); return 0; } @@ -813,9 +815,9 @@ void sock_set_sndtimeo(struct sock *sk, s64 secs) { lock_sock(sk); if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) - sk->sk_sndtimeo = secs * HZ; + WRITE_ONCE(sk->sk_sndtimeo, secs * HZ); else - sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; + WRITE_ONCE(sk->sk_sndtimeo, MAX_SCHEDULE_TIMEOUT); release_sock(sk); } EXPORT_SYMBOL(sock_set_sndtimeo); @@ -1721,12 +1723,14 @@ int sk_getsockopt(struct sock *sk, int level, int optname, case SO_RCVTIMEO_OLD: case SO_RCVTIMEO_NEW: - lv = sock_get_timeout(sk->sk_rcvtimeo, &v, SO_RCVTIMEO_OLD == optname); + lv = sock_get_timeout(READ_ONCE(sk->sk_rcvtimeo), &v, + SO_RCVTIMEO_OLD == optname); break; case SO_SNDTIMEO_OLD: case SO_SNDTIMEO_NEW: - lv = sock_get_timeout(sk->sk_sndtimeo, &v, SO_SNDTIMEO_OLD == optname); + lv = sock_get_timeout(READ_ONCE(sk->sk_sndtimeo), &v, + SO_SNDTIMEO_OLD == optname); break; case SO_RCVLOWAT: diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index af85a73c4c54..6fdba069f6bf 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -568,7 +568,7 @@ META_COLLECTOR(int_sk_rcvtimeo) *err = -1; return; } - dst->value = sk->sk_rcvtimeo / HZ; + dst->value = READ_ONCE(sk->sk_rcvtimeo) / HZ; } META_COLLECTOR(int_sk_sndtimeo) @@ -579,7 +579,7 @@ META_COLLECTOR(int_sk_sndtimeo) *err = -1; return; } - dst->value = sk->sk_sndtimeo / HZ; + dst->value = READ_ONCE(sk->sk_sndtimeo) / HZ; } META_COLLECTOR(int_sk_sendmsg_off) -- cgit v1.2.3 From 74bc084327c643499474ba75df485607da37dd6e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:13 +0000 Subject: net: add missing READ_ONCE(sk->sk_sndbuf) annotation In a prior commit, I forgot to change sk_getsockopt() when reading sk->sk_sndbuf locklessly. Fixes: e292f05e0df7 ("tcp: annotate sk->sk_sndbuf lockless reads") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index 264c99c190ac..ca43f7a30219 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1639,7 +1639,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_SNDBUF: - v.val = sk->sk_sndbuf; + v.val = READ_ONCE(sk->sk_sndbuf); break; case SO_RCVBUF: -- cgit v1.2.3 From b4b553253091cafe9ec38994acf42795e073bef5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:14 +0000 Subject: net: add missing READ_ONCE(sk->sk_rcvbuf) annotation In a prior commit, I forgot to change sk_getsockopt() when reading sk->sk_rcvbuf locklessly. Fixes: ebb3b78db7bf ("tcp: annotate sk->sk_rcvbuf lockless reads") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index ca43f7a30219..96616eb3869d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1643,7 +1643,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_RCVBUF: - v.val = sk->sk_rcvbuf; + v.val = READ_ONCE(sk->sk_rcvbuf); break; case SO_REUSEADDR: -- cgit v1.2.3 From 3c5b4d69c358a9275a8de98f87caf6eda644b086 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:15 +0000 Subject: net: annotate data-races around sk->sk_mark sk->sk_mark is often read while another thread could change the value. Fixes: 4a19ec5800fc ("[NET]: Introducing socket mark socket option.") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_sock.h | 7 ++++--- include/net/ip.h | 2 +- include/net/route.h | 4 ++-- net/can/raw.c | 2 +- net/core/sock.c | 4 ++-- net/dccp/ipv6.c | 4 ++-- net/ipv4/inet_diag.c | 4 ++-- net/ipv4/ip_output.c | 4 ++-- net/ipv4/route.c | 4 ++-- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/ping.c | 2 +- net/ipv6/raw.c | 4 ++-- net/ipv6/route.c | 7 ++++--- net/ipv6/tcp_ipv6.c | 6 +++--- net/ipv6/udp.c | 4 ++-- net/l2tp/l2tp_ip6.c | 2 +- net/mptcp/sockopt.c | 2 +- net/netfilter/nft_socket.c | 2 +- net/netfilter/xt_socket.c | 4 ++-- net/packet/af_packet.c | 6 +++--- net/smc/af_smc.c | 2 +- net/xdp/xsk.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- 23 files changed, 42 insertions(+), 40 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index caa20a905531..0bb32bfc6183 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -107,11 +107,12 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb) { - if (!sk->sk_mark && - READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept)) + u32 mark = READ_ONCE(sk->sk_mark); + + if (!mark && READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept)) return skb->mark; - return sk->sk_mark; + return mark; } static inline int inet_request_bound_dev_if(const struct sock *sk, diff --git a/include/net/ip.h b/include/net/ip.h index 50d435855ae2..332521170d9b 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -93,7 +93,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm, { ipcm_init(ipcm); - ipcm->sockc.mark = inet->sk.sk_mark; + ipcm->sockc.mark = READ_ONCE(inet->sk.sk_mark); ipcm->sockc.tsflags = inet->sk.sk_tsflags; ipcm->oif = READ_ONCE(inet->sk.sk_bound_dev_if); ipcm->addr = inet->inet_saddr; diff --git a/include/net/route.h b/include/net/route.h index 5a5c726472bd..8c2a8e7d8f8e 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -168,7 +168,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi __be16 dport, __be16 sport, __u8 proto, __u8 tos, int oif) { - flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, + flowi4_init_output(fl4, oif, sk ? READ_ONCE(sk->sk_mark) : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, daddr, saddr, dport, sport, sock_net_uid(net, sk)); @@ -301,7 +301,7 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, if (inet_sk(sk)->transparent) flow_flags |= FLOWI_FLAG_ANYSRC; - flowi4_init_output(fl4, oif, sk->sk_mark, ip_sock_rt_tos(sk), + flowi4_init_output(fl4, oif, READ_ONCE(sk->sk_mark), ip_sock_rt_tos(sk), ip_sock_rt_scope(sk), protocol, flow_flags, dst, src, dport, sport, sk->sk_uid); } diff --git a/net/can/raw.c b/net/can/raw.c index ba6b52b1d776..e10f59375659 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -865,7 +865,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) skb->dev = dev; skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; + skb->mark = READ_ONCE(sk->sk_mark); skb->tstamp = sockc.transmit_time; skb_setup_tx_timestamp(skb, sockc.tsflags); diff --git a/net/core/sock.c b/net/core/sock.c index 96616eb3869d..d831a3df2cef 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -990,7 +990,7 @@ EXPORT_SYMBOL(sock_set_rcvbuf); static void __sock_set_mark(struct sock *sk, u32 val) { if (val != sk->sk_mark) { - sk->sk_mark = val; + WRITE_ONCE(sk->sk_mark, val); sk_dst_reset(sk); } } @@ -1851,7 +1851,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, optval, optlen, len); case SO_MARK: - v.val = sk->sk_mark; + v.val = READ_ONCE(sk->sk_mark); break; case SO_RCVMARK: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 7249ef218178..d29d1163203d 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -238,8 +238,8 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req opt = ireq->ipv6_opt; if (!opt) opt = rcu_dereference(np->opt); - err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass, - sk->sk_priority); + err = ip6_xmit(sk, skb, &fl6, READ_ONCE(sk->sk_mark), opt, + np->tclass, sk->sk_priority); rcu_read_unlock(); err = net_xmit_eval(err); } diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index b812eb36f0e3..f7426926a104 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -150,7 +150,7 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, } #endif - if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) + if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, READ_ONCE(sk->sk_mark))) goto errout; if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) || @@ -799,7 +799,7 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) entry.ifindex = sk->sk_bound_dev_if; entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0; if (sk_fullsock(sk)) - entry.mark = sk->sk_mark; + entry.mark = READ_ONCE(sk->sk_mark); else if (sk->sk_state == TCP_NEW_SYN_RECV) entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark; else if (sk->sk_state == TCP_TIME_WAIT) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 6e70839257f7..bcdbf448324a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -186,7 +186,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk, skb->priority = sk->sk_priority; if (!skb->mark) - skb->mark = sk->sk_mark; + skb->mark = READ_ONCE(sk->sk_mark); /* Send it out. */ return ip_local_out(net, skb->sk, skb); @@ -529,7 +529,7 @@ packet_routed: /* TODO : should we use skb->sk here instead of sk ? */ skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; + skb->mark = READ_ONCE(sk->sk_mark); res = ip_local_out(net, sk, skb); rcu_read_unlock(); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 98d7e6ba7493..92fede388d52 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -518,7 +518,7 @@ static void __build_flow_key(const struct net *net, struct flowi4 *fl4, const struct inet_sock *inet = inet_sk(sk); oif = sk->sk_bound_dev_if; - mark = sk->sk_mark; + mark = READ_ONCE(sk->sk_mark); tos = ip_sock_rt_tos(sk); scope = ip_sock_rt_scope(sk); prot = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol; @@ -552,7 +552,7 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) inet_opt = rcu_dereference(inet->inet_opt); if (inet_opt && inet_opt->opt.srr) daddr = inet_opt->opt.faddr; - flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, + flowi4_init_output(fl4, sk->sk_bound_dev_if, READ_ONCE(sk->sk_mark), ip_sock_rt_tos(sk) & IPTOS_RT_MASK, ip_sock_rt_scope(sk), inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 069642014636..894653be033a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -931,7 +931,7 @@ static void tcp_v4_send_ack(const struct sock *sk, ctl_sk = this_cpu_read(ipv4_tcp_sk); sock_net_set(ctl_sk, net); ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? - inet_twsk(sk)->tw_mark : sk->sk_mark; + inet_twsk(sk)->tw_mark : READ_ONCE(sk->sk_mark); ctl_sk->sk_priority = (sk->sk_state == TCP_TIME_WAIT) ? inet_twsk(sk)->tw_priority : sk->sk_priority; transmit_time = tcp_transmit_time(sk); diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index f804c11e2146..c2c291827a2c 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -120,7 +120,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipcm6_init_sk(&ipc6, np); ipc6.sockc.tsflags = sk->sk_tsflags; - ipc6.sockc.mark = sk->sk_mark; + ipc6.sockc.mark = READ_ONCE(sk->sk_mark); fl6.flowi6_oif = oif; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ac1cef094c5f..39b7d727ba40 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -774,12 +774,12 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) */ memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_mark = READ_ONCE(sk->sk_mark); fl6.flowi6_uid = sk->sk_uid; ipcm6_init(&ipc6); ipc6.sockc.tsflags = sk->sk_tsflags; - ipc6.sockc.mark = sk->sk_mark; + ipc6.sockc.mark = fl6.flowi6_mark; if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 64e873f5895f..56a55585eb79 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2951,7 +2951,8 @@ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) if (!oif && skb->dev) oif = l3mdev_master_ifindex(skb->dev); - ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid); + ip6_update_pmtu(skb, sock_net(sk), mtu, oif, READ_ONCE(sk->sk_mark), + sk->sk_uid); dst = __sk_dst_get(sk); if (!dst || !dst->obsolete || @@ -3172,8 +3173,8 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif) void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk) { - ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark, - sk->sk_uid); + ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, + READ_ONCE(sk->sk_mark), sk->sk_uid); } EXPORT_SYMBOL_GPL(ip6_sk_redirect); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4714eb695913..3ec563742ac4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -564,8 +564,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, opt = ireq->ipv6_opt; if (!opt) opt = rcu_dereference(np->opt); - err = ip6_xmit(sk, skb, fl6, skb->mark ? : sk->sk_mark, opt, - tclass, sk->sk_priority); + err = ip6_xmit(sk, skb, fl6, skb->mark ? : READ_ONCE(sk->sk_mark), + opt, tclass, sk->sk_priority); rcu_read_unlock(); err = net_xmit_eval(err); } @@ -939,7 +939,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 if (sk->sk_state == TCP_TIME_WAIT) mark = inet_twsk(sk)->tw_mark; else - mark = sk->sk_mark; + mark = READ_ONCE(sk->sk_mark); skb_set_delivery_time(buff, tcp_transmit_time(sk), true); } if (txhash) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e5da5d1cb215..f787e6b8424c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -628,7 +628,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type == NDISC_REDIRECT) { if (tunnel) { ip6_redirect(skb, sock_net(sk), inet6_iif(skb), - sk->sk_mark, sk->sk_uid); + READ_ONCE(sk->sk_mark), sk->sk_uid); } else { ip6_sk_redirect(skb, sk); } @@ -1360,7 +1360,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipcm6_init(&ipc6); ipc6.gso_size = READ_ONCE(up->gso_size); ipc6.sockc.tsflags = sk->sk_tsflags; - ipc6.sockc.mark = sk->sk_mark; + ipc6.sockc.mark = READ_ONCE(sk->sk_mark); /* destination address check */ if (sin6) { diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index b1623f9c4f92..ff78217f0cb1 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -519,7 +519,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) /* Get and verify the address */ memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_mark = READ_ONCE(sk->sk_mark); fl6.flowi6_uid = sk->sk_uid; ipcm6_init(&ipc6); diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index 63f7a09335c5..a3f1fe810cc9 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -103,7 +103,7 @@ static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, in break; case SO_MARK: if (READ_ONCE(ssk->sk_mark) != sk->sk_mark) { - ssk->sk_mark = sk->sk_mark; + WRITE_ONCE(ssk->sk_mark, sk->sk_mark); sk_dst_reset(ssk); } break; diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c index 84def74698b7..9ed85be79452 100644 --- a/net/netfilter/nft_socket.c +++ b/net/netfilter/nft_socket.c @@ -107,7 +107,7 @@ static void nft_socket_eval(const struct nft_expr *expr, break; case NFT_SOCKET_MARK: if (sk_fullsock(sk)) { - *dest = sk->sk_mark; + *dest = READ_ONCE(sk->sk_mark); } else { regs->verdict.code = NFT_BREAK; return; diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 7013f55f05d1..76e01f292aaf 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -77,7 +77,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard && transparent && sk_fullsock(sk)) - pskb->mark = sk->sk_mark; + pskb->mark = READ_ONCE(sk->sk_mark); if (sk != skb->sk) sock_gen_put(sk); @@ -138,7 +138,7 @@ socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par) if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard && transparent && sk_fullsock(sk)) - pskb->mark = sk->sk_mark; + pskb->mark = READ_ONCE(sk->sk_mark); if (sk != skb->sk) sock_gen_put(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8e3ddec4c3d5..d9aa21a2b3a1 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2051,7 +2051,7 @@ retry: skb->protocol = proto; skb->dev = dev; skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; + skb->mark = READ_ONCE(sk->sk_mark); skb->tstamp = sockc.transmit_time; skb_setup_tx_timestamp(skb, sockc.tsflags); @@ -2586,7 +2586,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb->protocol = proto; skb->dev = dev; skb->priority = po->sk.sk_priority; - skb->mark = po->sk.sk_mark; + skb->mark = READ_ONCE(po->sk.sk_mark); skb->tstamp = sockc->transmit_time; skb_setup_tx_timestamp(skb, sockc->tsflags); skb_zcopy_set_nouarg(skb, ph.raw); @@ -2988,7 +2988,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) goto out_unlock; sockcm_init(&sockc, sk); - sockc.mark = sk->sk_mark; + sockc.mark = READ_ONCE(sk->sk_mark); if (msg->msg_controllen) { err = sock_cmsg_send(sk, msg, &sockc); if (unlikely(err)) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index a7f887d91d89..0c013d2b5d8f 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -445,7 +445,7 @@ static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, nsk->sk_rcvbuf = osk->sk_rcvbuf; nsk->sk_sndtimeo = osk->sk_sndtimeo; nsk->sk_rcvtimeo = osk->sk_rcvtimeo; - nsk->sk_mark = osk->sk_mark; + nsk->sk_mark = READ_ONCE(osk->sk_mark); nsk->sk_priority = osk->sk_priority; nsk->sk_rcvlowat = osk->sk_rcvlowat; nsk->sk_bound_dev_if = osk->sk_bound_dev_if; diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 31dca4ecb2c5..b89adb52a977 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -505,7 +505,7 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, skb->dev = dev; skb->priority = xs->sk.sk_priority; - skb->mark = xs->sk.sk_mark; + skb->mark = READ_ONCE(xs->sk.sk_mark); skb_shinfo(skb)->destructor_arg = (void *)(long)desc->addr; skb->destructor = xsk_destruct_skb; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index e7617c9959c3..d6b405782b63 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2250,7 +2250,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, match = xfrm_selector_match(&pol->selector, fl, family); if (match) { - if ((sk->sk_mark & pol->mark.m) != pol->mark.v || + if ((READ_ONCE(sk->sk_mark) & pol->mark.m) != pol->mark.v || pol->if_id != if_id) { pol = NULL; goto out; -- cgit v1.2.3 From 11695c6e966b0ec7ed1d16777d294cef865a5c91 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:16 +0000 Subject: net: add missing data-race annotations around sk->sk_peek_off sk_getsockopt() runs locklessly, thus we need to annotate the read of sk->sk_peek_off. While we are at it, add corresponding annotations to sk_set_peek_off() and unix_set_peek_off(). Fixes: b9bb53f3836f ("sock: convert sk_peek_offset functions to WRITE_ONCE") Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller --- net/core/sock.c | 4 ++-- net/unix/af_unix.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index d831a3df2cef..d57acaee42d4 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1870,7 +1870,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, if (!sock->ops->set_peek_off) return -EOPNOTSUPP; - v.val = sk->sk_peek_off; + v.val = READ_ONCE(sk->sk_peek_off); break; case SO_NOFCS: v.val = sock_flag(sk, SOCK_NOFCS); @@ -3179,7 +3179,7 @@ EXPORT_SYMBOL(__sk_mem_reclaim); int sk_set_peek_off(struct sock *sk, int val) { - sk->sk_peek_off = val; + WRITE_ONCE(sk->sk_peek_off, val); return 0; } EXPORT_SYMBOL_GPL(sk_set_peek_off); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 78585217f61a..86930a8ed012 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -790,7 +790,7 @@ static int unix_set_peek_off(struct sock *sk, int val) if (mutex_lock_interruptible(&u->iolock)) return -EINTR; - sk->sk_peek_off = val; + WRITE_ONCE(sk->sk_peek_off, val); mutex_unlock(&u->iolock); return 0; -- cgit v1.2.3 From e5f0d2dd3c2faa671711dac6d3ff3cef307bcfe3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:17 +0000 Subject: net: add missing data-race annotation for sk_ll_usec In a prior commit I forgot that sk_getsockopt() reads sk->sk_ll_usec without holding a lock. Fixes: 0dbffbb5335a ("net: annotate data race around sk_ll_usec") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index d57acaee42d4..f11e19c7edfb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1900,7 +1900,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_NET_RX_BUSY_POLL case SO_BUSY_POLL: - v.val = sk->sk_ll_usec; + v.val = READ_ONCE(sk->sk_ll_usec); break; case SO_PREFER_BUSY_POLL: v.val = READ_ONCE(sk->sk_prefer_busy_poll); -- cgit v1.2.3 From 8bf43be799d4b242ea552a14db10456446be843e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jul 2023 15:03:18 +0000 Subject: net: annotate data-races around sk->sk_priority sk_getsockopt() runs locklessly. This means sk->sk_priority can be read while other threads are changing its value. Other reads also happen without socket lock being held. Add missing annotations where needed. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 6 +++--- net/ipv4/ip_output.c | 4 ++-- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/tcp_ipv6.c | 3 ++- net/packet/af_packet.c | 6 +++--- 8 files changed, 14 insertions(+), 13 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index f11e19c7edfb..6d4f28efe29a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -806,7 +806,7 @@ EXPORT_SYMBOL(sock_no_linger); void sock_set_priority(struct sock *sk, u32 priority) { lock_sock(sk); - sk->sk_priority = priority; + WRITE_ONCE(sk->sk_priority, priority); release_sock(sk); } EXPORT_SYMBOL(sock_set_priority); @@ -1216,7 +1216,7 @@ set_sndbuf: if ((val >= 0 && val <= 6) || sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) || sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - sk->sk_priority = val; + WRITE_ONCE(sk->sk_priority, val); else ret = -EPERM; break; @@ -1685,7 +1685,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, break; case SO_PRIORITY: - v.val = sk->sk_priority; + v.val = READ_ONCE(sk->sk_priority); break; case SO_LINGER: diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index bcdbf448324a..54d2d3a2d850 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -184,7 +184,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk, ip_options_build(skb, &opt->opt, daddr, rt); } - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); if (!skb->mark) skb->mark = READ_ONCE(sk->sk_mark); @@ -528,7 +528,7 @@ packet_routed: skb_shinfo(skb)->gso_segs ?: 1); /* TODO : should we use skb->sk here instead of sk ? */ - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); skb->mark = READ_ONCE(sk->sk_mark); res = ip_local_out(net, sk, skb); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 8e97d8d4cc9d..d41bce8927b2 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -592,7 +592,7 @@ void __ip_sock_set_tos(struct sock *sk, int val) } if (inet_sk(sk)->tos != val) { inet_sk(sk)->tos = val; - sk->sk_priority = rt_tos2priority(val); + WRITE_ONCE(sk->sk_priority, rt_tos2priority(val)); sk_dst_reset(sk); } } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 7782ff5e6539..cb381f5aa464 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -348,7 +348,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, goto error; skb_reserve(skb, hlen); - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc->mark; skb->tstamp = sockc->transmit_time; skb_dst_set(skb, &rt->dst); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 894653be033a..a59cc4b83861 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -933,7 +933,7 @@ static void tcp_v4_send_ack(const struct sock *sk, ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? inet_twsk(sk)->tw_mark : READ_ONCE(sk->sk_mark); ctl_sk->sk_priority = (sk->sk_state == TCP_TIME_WAIT) ? - inet_twsk(sk)->tw_priority : sk->sk_priority; + inet_twsk(sk)->tw_priority : READ_ONCE(sk->sk_priority); transmit_time = tcp_transmit_time(sk); ip_send_unicast_reply(ctl_sk, skb, &TCP_SKB_CB(skb)->header.h4.opt, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 39b7d727ba40..49381f35b623 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -614,7 +614,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, skb_reserve(skb, hlen); skb->protocol = htons(ETH_P_IPV6); - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc->mark; skb->tstamp = sockc->transmit_time; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3ec563742ac4..6e86721e1cdb 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1128,7 +1128,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, READ_ONCE(req->ts_recent), sk->sk_bound_dev_if, tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, l3index), - ipv6_get_dsfield(ipv6_hdr(skb)), 0, sk->sk_priority, + ipv6_get_dsfield(ipv6_hdr(skb)), 0, + READ_ONCE(sk->sk_priority), READ_ONCE(tcp_rsk(req)->txhash)); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d9aa21a2b3a1..a4631cb457a9 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2050,7 +2050,7 @@ retry: skb->protocol = proto; skb->dev = dev; - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); skb->mark = READ_ONCE(sk->sk_mark); skb->tstamp = sockc.transmit_time; @@ -2585,7 +2585,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb->protocol = proto; skb->dev = dev; - skb->priority = po->sk.sk_priority; + skb->priority = READ_ONCE(po->sk.sk_priority); skb->mark = READ_ONCE(po->sk.sk_mark); skb->tstamp = sockc->transmit_time; skb_setup_tx_timestamp(skb, sockc->tsflags); @@ -3061,7 +3061,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) skb->protocol = proto; skb->dev = dev; - skb->priority = sk->sk_priority; + skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc.mark; skb->tstamp = sockc.transmit_time; -- cgit v1.2.3 From 101df45e7ec36f470559c8fdab8e272cb991ef42 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 27 Jul 2023 17:21:17 +0100 Subject: nfsd: Fix reading via splice nfsd_splice_actor() has a clause in its loop that chops up a compound page into individual pages such that if the same page is seen twice in a row, it is discarded the second time. This is a problem with the advent of shmem_splice_read() as that inserts zero_pages into the pipe in lieu of pages that aren't present in the pagecache. Fix this by assuming that the last page is being extended only if the currently stored length + starting offset is not currently on a page boundary. This can be tested by NFS-exporting a tmpfs filesystem on the test machine and truncating it to more than a page in size (eg. truncate -s 8192) and then reading it by NFS. The first page will be all zeros, but thereafter garbage will be read. Note: I wonder if we can ever get a situation now where we get a splice that gives us contiguous parts of a page in separate actor calls. As NFSD can only be splicing from a file (I think), there are only three sources of the page: copy_splice_read(), shmem_splice_read() and file_splice_read(). The first allocates pages for the data it reads, so the problem cannot occur; the second should never see a partial page; and the third waits for each page to become available before we're allowed to read from it. Fixes: bd194b187115 ("shmem: Implement splice-read") Reported-by: Chuck Lever Signed-off-by: David Howells Reviewed-by: Jeff Layton Reviewed-by: NeilBrown cc: Hugh Dickins cc: Jens Axboe cc: Matthew Wilcox cc: linux-nfs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org Signed-off-by: Chuck Lever --- fs/nfsd/vfs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 59b7d60ae33e..ee3bbaa79478 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -956,10 +956,13 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, last_page = page + (offset + sd->len - 1) / PAGE_SIZE; for (page += offset / PAGE_SIZE; page <= last_page; page++) { /* - * Skip page replacement when extending the contents - * of the current page. + * Skip page replacement when extending the contents of the + * current page. But note that we may get two zero_pages in a + * row from shmem. */ - if (page == *(rqstp->rq_next_page - 1)) + if (page == *(rqstp->rq_next_page - 1) && + offset_in_page(rqstp->rq_res.page_base + + rqstp->rq_res.page_len)) continue; if (unlikely(!svc_rqst_replace_page(rqstp, page))) return -EIO; -- cgit v1.2.3 From e739718444f7bf2fa3d70d101761ad83056ca628 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 28 Jul 2023 17:07:05 -0700 Subject: net/sched: taprio: Limit TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME to INT_MAX. syzkaller found zero division error [0] in div_s64_rem() called from get_cycle_time_elapsed(), where sched->cycle_time is the divisor. We have tests in parse_taprio_schedule() so that cycle_time will never be 0, and actually cycle_time is not 0 in get_cycle_time_elapsed(). The problem is that the types of divisor are different; cycle_time is s64, but the argument of div_s64_rem() is s32. syzkaller fed this input and 0x100000000 is cast to s32 to be 0. @TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME={0xc, 0x8, 0x100000000} We use s64 for cycle_time to cast it to ktime_t, so let's keep it and set max for cycle_time. While at it, we prevent overflow in setup_txtime() and add another test in parse_taprio_schedule() to check if cycle_time overflows. Also, we add a new tdc test case for this issue. [0]: divide error: 0000 [#1] PREEMPT SMP KASAN NOPTI CPU: 1 PID: 103 Comm: kworker/1:3 Not tainted 6.5.0-rc1-00330-g60cc1f7d0605 #3 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 Workqueue: ipv6_addrconf addrconf_dad_work RIP: 0010:div_s64_rem include/linux/math64.h:42 [inline] RIP: 0010:get_cycle_time_elapsed net/sched/sch_taprio.c:223 [inline] RIP: 0010:find_entry_to_transmit+0x252/0x7e0 net/sched/sch_taprio.c:344 Code: 3c 02 00 0f 85 5e 05 00 00 48 8b 4c 24 08 4d 8b bd 40 01 00 00 48 8b 7c 24 48 48 89 c8 4c 29 f8 48 63 f7 48 99 48 89 74 24 70 <48> f7 fe 48 29 d1 48 8d 04 0f 49 89 cc 48 89 44 24 20 49 8d 85 10 RSP: 0018:ffffc90000acf260 EFLAGS: 00010206 RAX: 177450e0347560cf RBX: 0000000000000000 RCX: 177450e0347560cf RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000100000000 RBP: 0000000000000056 R08: 0000000000000000 R09: ffffed10020a0934 R10: ffff8880105049a7 R11: ffff88806cf3a520 R12: ffff888010504800 R13: ffff88800c00d800 R14: ffff8880105049a0 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88806cf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f0edf84f0e8 CR3: 000000000d73c002 CR4: 0000000000770ee0 PKRU: 55555554 Call Trace: get_packet_txtime net/sched/sch_taprio.c:508 [inline] taprio_enqueue_one+0x900/0xff0 net/sched/sch_taprio.c:577 taprio_enqueue+0x378/0xae0 net/sched/sch_taprio.c:658 dev_qdisc_enqueue+0x46/0x170 net/core/dev.c:3732 __dev_xmit_skb net/core/dev.c:3821 [inline] __dev_queue_xmit+0x1b2f/0x3000 net/core/dev.c:4169 dev_queue_xmit include/linux/netdevice.h:3088 [inline] neigh_resolve_output net/core/neighbour.c:1552 [inline] neigh_resolve_output+0x4a7/0x780 net/core/neighbour.c:1532 neigh_output include/net/neighbour.h:544 [inline] ip6_finish_output2+0x924/0x17d0 net/ipv6/ip6_output.c:135 __ip6_finish_output+0x620/0xaa0 net/ipv6/ip6_output.c:196 ip6_finish_output net/ipv6/ip6_output.c:207 [inline] NF_HOOK_COND include/linux/netfilter.h:292 [inline] ip6_output+0x206/0x410 net/ipv6/ip6_output.c:228 dst_output include/net/dst.h:458 [inline] NF_HOOK.constprop.0+0xea/0x260 include/linux/netfilter.h:303 ndisc_send_skb+0x872/0xe80 net/ipv6/ndisc.c:508 ndisc_send_ns+0xb5/0x130 net/ipv6/ndisc.c:666 addrconf_dad_work+0xc14/0x13f0 net/ipv6/addrconf.c:4175 process_one_work+0x92c/0x13a0 kernel/workqueue.c:2597 worker_thread+0x60f/0x1240 kernel/workqueue.c:2748 kthread+0x2fe/0x3f0 kernel/kthread.c:389 ret_from_fork+0x2c/0x50 arch/x86/entry/entry_64.S:308 Modules linked in: Fixes: 4cfd5779bd6e ("taprio: Add support for txtime-assist mode") Reported-by: syzkaller Signed-off-by: Kuniyuki Iwashima Co-developed-by: Eric Dumazet Co-developed-by: Pedro Tammela Acked-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- net/sched/sch_taprio.c | 15 +++++++++++-- .../tc-testing/tc-tests/qdiscs/taprio.json | 25 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 717ae51d94a0..8c9cfff7fd05 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -1015,6 +1015,11 @@ static const struct nla_policy taprio_tc_policy[TCA_TAPRIO_TC_ENTRY_MAX + 1] = { TC_FP_PREEMPTIBLE), }; +static struct netlink_range_validation_signed taprio_cycle_time_range = { + .min = 0, + .max = INT_MAX, +}; + static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = { [TCA_TAPRIO_ATTR_PRIOMAP] = { .len = sizeof(struct tc_mqprio_qopt) @@ -1023,7 +1028,8 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = { [TCA_TAPRIO_ATTR_SCHED_BASE_TIME] = { .type = NLA_S64 }, [TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] = { .type = NLA_NESTED }, [TCA_TAPRIO_ATTR_SCHED_CLOCKID] = { .type = NLA_S32 }, - [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME] = { .type = NLA_S64 }, + [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME] = + NLA_POLICY_FULL_RANGE_SIGNED(NLA_S64, &taprio_cycle_time_range), [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION] = { .type = NLA_S64 }, [TCA_TAPRIO_ATTR_FLAGS] = { .type = NLA_U32 }, [TCA_TAPRIO_ATTR_TXTIME_DELAY] = { .type = NLA_U32 }, @@ -1159,6 +1165,11 @@ static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb, return -EINVAL; } + if (cycle < 0 || cycle > INT_MAX) { + NL_SET_ERR_MSG(extack, "'cycle_time' is too big"); + return -EINVAL; + } + new->cycle_time = cycle; } @@ -1347,7 +1358,7 @@ static void setup_txtime(struct taprio_sched *q, struct sched_gate_list *sched, ktime_t base) { struct sched_entry *entry; - u32 interval = 0; + u64 interval = 0; list_for_each_entry(entry, &sched->entries, list) { entry->next_txtime = ktime_add_ns(base, interval); diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json index a44455372646..08d4861c2e78 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json @@ -131,5 +131,30 @@ "teardown": [ "echo \"1\" > /sys/bus/netdevsim/del_device" ] + }, + { + "id": "3e1e", + "name": "Add taprio Qdisc with an invalid cycle-time", + "category": [ + "qdisc", + "taprio" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "echo \"1 1 8\" > /sys/bus/netdevsim/new_device", + "$TC qdisc add dev $ETH root handle 1: taprio num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@0 1@0 base-time 1000000000 sched-entry S 01 300000 flags 0x1 clockid CLOCK_TAI cycle-time 4294967296 || /bin/true", + "$IP link set dev $ETH up", + "$IP addr add 10.10.10.10/24 dev $ETH" + ], + "cmdUnderTest": "/bin/true", + "expExitCode": "0", + "verifyCmd": "$TC qdisc show dev $ETH", + "matchPattern": "qdisc taprio 1: root refcnt", + "matchCount": "0", + "teardown": [ + "echo \"1\" > /sys/bus/netdevsim/del_device" + ] } ] -- cgit v1.2.3 From 8469c7f5472fe5f77fc31c8f10f23d5aad987231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 29 Jul 2023 13:10:45 +0200 Subject: dt-bindings: net: mediatek,net: fixup MAC binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Use unevaluatedProperties It's needed to allow ethernet-controller.yaml properties work correctly. 2. Drop unneeded phy-handle/phy-mode 3. Don't require phy-handle Some SoCs may use fixed link. For in-kernel MT7621 DTS files this fixes following errors: arch/mips/boot/dts/ralink/mt7621-tplink-hc220-g5-v1.dtb: ethernet@1e100000: mac@0: 'fixed-link' does not match any of the regexes: 'pinctrl-[0-9]+' From schema: Documentation/devicetree/bindings/net/mediatek,net.yaml arch/mips/boot/dts/ralink/mt7621-tplink-hc220-g5-v1.dtb: ethernet@1e100000: mac@0: 'phy-handle' is a required property From schema: Documentation/devicetree/bindings/net/mediatek,net.yaml arch/mips/boot/dts/ralink/mt7621-tplink-hc220-g5-v1.dtb: ethernet@1e100000: mac@1: 'fixed-link' does not match any of the regexes: 'pinctrl-[0-9]+' From schema: Documentation/devicetree/bindings/net/mediatek,net.yaml arch/mips/boot/dts/ralink/mt7621-tplink-hc220-g5-v1.dtb: ethernet@1e100000: mac@1: 'phy-handle' is a required property From schema: Documentation/devicetree/bindings/net/mediatek,net.yaml Signed-off-by: RafaƂ MiƂecki Reviewed-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/mediatek,net.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/net/mediatek,net.yaml b/Documentation/devicetree/bindings/net/mediatek,net.yaml index acb2b2ac4fe1..31cc0c412805 100644 --- a/Documentation/devicetree/bindings/net/mediatek,net.yaml +++ b/Documentation/devicetree/bindings/net/mediatek,net.yaml @@ -293,7 +293,7 @@ allOf: patternProperties: "^mac@[0-1]$": type: object - additionalProperties: false + unevaluatedProperties: false allOf: - $ref: ethernet-controller.yaml# description: @@ -305,14 +305,9 @@ patternProperties: reg: maxItems: 1 - phy-handle: true - - phy-mode: true - required: - reg - compatible - - phy-handle required: - compatible -- cgit v1.2.3 From 186b169cf1e4be85aa212a893ea783a543400979 Mon Sep 17 00:00:00 2001 From: Michael Guralnik Date: Wed, 19 Jul 2023 12:02:41 +0300 Subject: RDMA/umem: Set iova in ODP flow Fixing the ODP registration flow to set the iova correctly. The calculation in ib_umem_num_dma_blocks() function assumes the iova of the umem is set correctly. When iova is not set, the calculation in ib_umem_num_dma_blocks() is equivalent to length/page_size, which is true only when memory is aligned. For unaligned memory, iova must be set for the ALIGN() in the ib_umem_num_dma_blocks() to take effect and return a correct value. mlx5_ib uses ib_umem_num_dma_blocks() to decide the mkey size to use for the MR. Without this fix, when registering unaligned ODP MR, a wrong size mkey might be chosen and this might cause the UMR to fail. UMR would fail over insufficient size to update the mkey translation: infiniband mlx5_0: dump_cqe:273:(pid 0): dump error cqe 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030: 00 00 00 00 0f 00 78 06 25 00 00 58 00 da ac d2 infiniband mlx5_0: mlx5_ib_post_send_wait:806:(pid 20311): reg umr failed (6) infiniband mlx5_0: pagefault_real_mr:661:(pid 20311): Failed to update mkey page tables Fixes: f0093fb1a7cb ("RDMA/mlx5: Move mlx5_ib_cont_pages() to the creation of the mlx5_ib_mr") Fixes: a665aca89a41 ("RDMA/umem: Split ib_umem_num_pages() into ib_umem_num_dma_blocks()") Signed-off-by: Artemy Kovalyov Signed-off-by: Michael Guralnik Link: https://lore.kernel.org/r/3d4be7ca2155bf239dd8c00a2d25974a92c26ab8.1689757344.git.leon@kernel.org Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/umem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 755a9c57db6f..f9ab671c8eda 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -85,6 +85,8 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, dma_addr_t mask; int i; + umem->iova = va = virt; + if (umem->is_odp) { unsigned int page_size = BIT(to_ib_umem_odp(umem)->page_shift); @@ -100,7 +102,6 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, */ pgsz_bitmap &= GENMASK(BITS_PER_LONG - 1, PAGE_SHIFT); - umem->iova = va = virt; /* The best result is the smallest page size that results in the minimum * number of required pages. Compute the largest page size that could * work based on VA address bits that don't change. -- cgit v1.2.3 From 1e7417c188d0a83fb385ba2dbe35fd2563f2b6f3 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Wed, 26 Jul 2023 16:14:07 +0800 Subject: net: usb: lan78xx: reorder cleanup operations to avoid UAF bugs The timer dev->stat_monitor can schedule the delayed work dev->wq and the delayed work dev->wq can also arm the dev->stat_monitor timer. When the device is detaching, the net_device will be deallocated. but the net_device private data could still be dereferenced in delayed work or timer handler. As a result, the UAF bugs will happen. One racy situation is shown below: (Thread 1) | (Thread 2) lan78xx_stat_monitor() | ... | lan78xx_disconnect() lan78xx_defer_kevent() | ... ... | cancel_delayed_work_sync(&dev->wq); schedule_delayed_work() | ... (wait some time) | free_netdev(net); //free net_device lan78xx_delayedwork() | //use net_device private data | dev-> //use | Although we use cancel_delayed_work_sync() to cancel the delayed work in lan78xx_disconnect(), it could still be scheduled in timer handler lan78xx_stat_monitor(). Another racy situation is shown below: (Thread 1) | (Thread 2) lan78xx_delayedwork | mod_timer() | lan78xx_disconnect() | cancel_delayed_work_sync() (wait some time) | if (timer_pending(&dev->stat_monitor)) | del_timer_sync(&dev->stat_monitor); lan78xx_stat_monitor() | ... lan78xx_defer_kevent() | free_netdev(net); //free //use net_device private data| dev-> //use | Although we use del_timer_sync() to delete the timer, the function timer_pending() returns 0 when the timer is activated. As a result, the del_timer_sync() will not be executed and the timer could be re-armed. In order to mitigate this bug, We use timer_shutdown_sync() to shutdown the timer and then use cancel_delayed_work_sync() to cancel the delayed work. As a result, the net_device could be deallocated safely. What's more, the dev->flags is set to EVENT_DEV_DISCONNECT in lan78xx_disconnect(). But it could still be set to EVENT_STAT_UPDATE in lan78xx_stat_monitor(). So this patch put the set_bit() behind timer_shutdown_sync(). Fixes: 77dfff5bb7e2 ("lan78xx: Fix race condition in disconnect handling") Signed-off-by: Duoming Zhou Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index c458c030fadf..59cde06aa7f6 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -4224,8 +4224,6 @@ static void lan78xx_disconnect(struct usb_interface *intf) if (!dev) return; - set_bit(EVENT_DEV_DISCONNECT, &dev->flags); - netif_napi_del(&dev->napi); udev = interface_to_usbdev(intf); @@ -4233,6 +4231,8 @@ static void lan78xx_disconnect(struct usb_interface *intf) unregister_netdev(net); + timer_shutdown_sync(&dev->stat_monitor); + set_bit(EVENT_DEV_DISCONNECT, &dev->flags); cancel_delayed_work_sync(&dev->wq); phydev = net->phydev; @@ -4247,9 +4247,6 @@ static void lan78xx_disconnect(struct usb_interface *intf) usb_scuttle_anchored_urbs(&dev->deferred); - if (timer_pending(&dev->stat_monitor)) - del_timer_sync(&dev->stat_monitor); - lan78xx_unbind(dev, intf); lan78xx_free_tx_resources(dev); -- cgit v1.2.3 From 8897a1475f278eb36d76df9684466b17b8dd4cab Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:22 +0000 Subject: ASoC: rsnd: use DAI driver ID instead of DAI ID Current rsnd is using DAI ID to get own priv data without setting driver->id. It was no problem for Single Component, but will be problem in case of Multi Component, because it is not a DAI serial number. struct snd_soc_dai *snd_soc_register_dai(...) { ... if (dai_drv->id) dai->id = dai_drv->id; else dai->id = component->num_dai; ... } This patch sets driver->id, and get serial number. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wmyqb1mm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 6a522e6dd85a..f3f17b784025 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1378,6 +1378,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; drv->pcm_new = rsnd_pcm_new; + drv->id = dai_i; io_playback->rdai = rdai; io_capture->rdai = rdai; -- cgit v1.2.3 From 6328489c135b60380b9e12b4d23854433e96a8b0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:31 +0000 Subject: ASoC: rsnd: cleanup rsnd_dai_of_node() It calls rsnd_dai_of_node() to know it was called from Audio Graph Card/Card2, or from Simple Audio Card. And after that, it gets number of related DAIs. To be more simple code, this patch merges these. This is prepare for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8eab1md.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f3f17b784025..a87d7fa55f7b 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1261,7 +1261,7 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name } static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, - int *is_graph) + int *nr, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; @@ -1274,22 +1274,30 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, * parse both previous dai (= rcar_sound,dai), and * graph dai (= ports/port) */ + + /* + * Simple-Card + */ dai_node = of_get_child_by_name(np, RSND_NODE_DAI); if (dai_node) { + *nr = of_get_child_count(dai_node); ret = dai_node; goto of_node_compatible; } - ret = np; - + /* + * Audio-Graph-Card + */ dai_node = of_graph_get_next_endpoint(np, NULL); - if (dai_node) - goto of_node_graph; + if (dai_node) { + *nr = of_graph_get_endpoint_count(np); + *is_graph = 1; + ret = np; + goto of_node_compatible; + } return NULL; -of_node_graph: - *is_graph = 1; of_node_compatible: of_node_put(dai_node); @@ -1447,16 +1455,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai *rdai; - int nr; + int nr = 0; int is_graph; int dai_i; - dai_node = rsnd_dai_of_node(priv, &is_graph); - if (is_graph) - nr = of_graph_get_endpoint_count(dai_node); - else - nr = of_get_child_count(dai_node); - + dai_node = rsnd_dai_of_node(priv, &nr, &is_graph); if (!nr) return -EINVAL; -- cgit v1.2.3 From 547b02f74e4ac1e7d295a6266d5bc93a647cd4ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:39 +0000 Subject: ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2 +-- Basic Board ---------+ |+--------+ +------+| || CPU ch0| <--> |CodecA|| || ch1| <-+ +------+| |+--------+ | | +-------------|----------+ +-- expansion board -----+ | | +------+| | +->|CodecB|| | +------+| +------------------------+ In above HW connection case, we intuitively think we want to handle these as "2 Sound Cards". card0,0: CPU-ch0 - CodecA card1,0: CPU-ch1 - CodecB But, we needed to handle it as "1 big Sound Card", because of Component vs Card limitation. card0,0: CPU-ch0 - CodecA card0,1: CPU-ch1 - CodecB This patch enables multi Component to handle multi Cards. To support it, it needs - Fill dai_args for each DAI on snd_soc_dai_driver - Parse DT for each Component (Simple Card/Audio Graph Card) Ex) Simple Card rcar_sound { ... /* Component0 */ rcar_sound,dai@0 { ... }; /* Component1 */ rcar_sound,dai@1 { ... }; }; Ex) Audio Graph Card/Card2 rcar_sound { /* Component0 */ ports@0 { ... }; /* Component1 */ ports@1 { ... }; }; Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tttub1m4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 134 ++++++++++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 4 ++ 2 files changed, 95 insertions(+), 43 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a87d7fa55f7b..9f3d97bc177a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1260,13 +1260,13 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name return i; } -static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, - int *nr, int *is_graph) +static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct device_node *dai_node; - struct device_node *ret; + struct device_node *ports, *node; + int nr = 0; + int i = 0; *is_graph = 0; @@ -1278,30 +1278,47 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, /* * Simple-Card */ - dai_node = of_get_child_by_name(np, RSND_NODE_DAI); - if (dai_node) { - *nr = of_get_child_count(dai_node); - ret = dai_node; - goto of_node_compatible; + node = of_get_child_by_name(np, RSND_NODE_DAI); + if (!node) + goto audio_graph; + + of_node_put(node); + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; + + priv->component_dais[i] = of_get_child_count(node); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + break; + } } + return nr; + +audio_graph: /* * Audio-Graph-Card */ - dai_node = of_graph_get_next_endpoint(np, NULL); - if (dai_node) { - *nr = of_graph_get_endpoint_count(np); - *is_graph = 1; - ret = np; - goto of_node_compatible; + for_each_child_of_node(np, ports) { + if (!of_node_name_eq(ports, "ports") && + !of_node_name_eq(ports, "port")) + continue; + priv->component_dais[i] = of_graph_get_endpoint_count(ports); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + break; + } } - return NULL; - -of_node_compatible: - of_node_put(dai_node); + *is_graph = 1; - return ret; + return nr; } @@ -1365,6 +1382,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, + struct device_node *node_np, + uint32_t node_arg, int dai_i) { struct rsnd_dai_stream *io_playback; @@ -1382,11 +1401,17 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + /* for multi Component */ + rdai->dai_args.np = node_np; + rdai->dai_args.args_count = 1; + rdai->dai_args.args[0] = node_arg; + rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; drv->pcm_new = rsnd_pcm_new; drv->id = dai_i; + drv->dai_args = &rdai->dai_args; io_playback->rdai = rdai; io_capture->rdai = rdai; @@ -1450,16 +1475,15 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, static int rsnd_dai_probe(struct rsnd_priv *priv) { - struct device_node *dai_node; - struct device_node *dai_np; struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; struct rsnd_dai *rdai; int nr = 0; int is_graph; int dai_i; - dai_node = rsnd_dai_of_node(priv, &nr, &is_graph); + nr = rsnd_dai_of_node(priv, &is_graph); if (!nr) return -EINVAL; @@ -1477,26 +1501,42 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) */ dai_i = 0; if (is_graph) { - for_each_endpoint_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); - rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + struct device_node *ports; + struct device_node *dai_np; + + for_each_child_of_node(np, ports) { + if (!of_node_name_eq(ports, "ports") && + !of_node_name_eq(ports, "port")) + continue; + for_each_endpoint_of_node(ports, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } else { - for_each_child_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); + struct device_node *node; + struct device_node *dai_np; + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; - rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); - rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + for_each_child_of_node(node, dai_np) { + __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } @@ -1926,6 +1966,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_dai_probe, }; int ret, i; + int ci; /* * init priv data @@ -1962,11 +2003,18 @@ static int rsnd_probe(struct platform_device *pdev) /* * asoc register */ - ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, - priv->daidrv, rsnd_rdai_nr(priv)); - if (ret < 0) { - dev_err(dev, "cannot snd dai register\n"); - goto exit_snd_probe; + ci = 0; + for (i = 0; priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, + priv->daidrv + ci, nr); + if (ret < 0) { + dev_err(dev, "cannot snd component register\n"); + goto exit_snd_probe; + } + + ci += nr; } pm_runtime_enable(dev); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 239705d52517..43c0d675cc34 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -545,6 +545,7 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; struct snd_pcm_hw_constraint_list constraint; + struct of_phandle_args dai_args; int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ @@ -702,6 +703,9 @@ struct rsnd_priv { struct snd_soc_dai_driver *daidrv; struct rsnd_dai *rdai; int rdai_nr; + +#define RSND_MAX_COMPONENT 3 + int component_dais[RSND_MAX_COMPONENT]; }; #define rsnd_priv_to_pdev(priv) ((priv)->pdev) -- cgit v1.2.3 From 289f6e3bdc3f3cf752794be3820b0e5c394b2733 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:56 +0000 Subject: ASoC: dt-bindings: renesas,rsnd.yaml: add common port-def renesas,rsnd uses both "ports" has "port", and these are very similar. To avoid duplicated definitions, this patch adds common port-def. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sf9eb1ln.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.yaml | 38 +++++++++------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 8a821dec9526..d9808b130e8d 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -9,6 +9,20 @@ title: Renesas R-Car Sound Driver maintainers: - Kuninori Morimoto +definitions: + port-def: + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + "^endpoint(@[0-9a-f]+)?": + $ref: audio-graph-port.yaml#/definitions/endpoint-base + properties: + playback: + $ref: /schemas/types.yaml#/definitions/phandle-array + capture: + $ref: /schemas/types.yaml#/definitions/phandle-array + unevaluatedProperties: false + properties: compatible: @@ -108,30 +122,10 @@ properties: unevaluatedProperties: false patternProperties: '^port(@[0-9a-f]+)?$': - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false + $ref: "#/definitions/port-def" port: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false + $ref: "#/definitions/port-def" rcar_sound,dvc: description: DVC subnode. -- cgit v1.2.3 From 1638290414bd68a87acae125e9fe3e419267bd01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:22:01 +0000 Subject: ASoC: dt-bindings: renesas,rsnd.yaml: enable multi ports for multi Component support To enable multi Component support, "multi ports" is needed for Audio Graph Card/Card2, and "multi rcar_sound,dai" is needed for Simple Audio Card. This patch enable these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0oyb1li.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.yaml | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index d9808b130e8d..13a5a0a10fe6 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -91,6 +91,12 @@ properties: it must be 1 if your system has audio_clkout0/1/2/3 enum: [0, 1] + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + clock-frequency: description: for audio_clkout0/1/2/3 @@ -117,13 +123,7 @@ properties: description: List of necessary clock names. # details are defined below - ports: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - '^port(@[0-9a-f]+)?$': - $ref: "#/definitions/port-def" - + # ports is below port: $ref: "#/definitions/port-def" @@ -242,8 +242,9 @@ properties: - interrupts additionalProperties: false +patternProperties: # For DAI base - rcar_sound,dai: + 'rcar_sound,dai(@[0-9a-f]+)?$': description: DAI subnode. type: object patternProperties: @@ -263,6 +264,13 @@ properties: - capture additionalProperties: false + 'ports(@[0-9a-f]+)?$': + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + '^port(@[0-9a-f]+)?$': + $ref: "#/definitions/port-def" + required: - compatible - reg -- cgit v1.2.3 From cd8ee8aba1f3b5dd4118dc8cea05b73734983288 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Sun, 30 Jul 2023 22:17:42 +0300 Subject: dt-bindings: sound: gtm601: convert to YAML Convert GTM601 binding to the YAML format. Signed-off-by: David Heidelberg Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730191742.117013-1-david@ixit.cz Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/gtm601.txt | 19 ---------- .../devicetree/bindings/sound/option,gtm601.yaml | 40 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/gtm601.txt create mode 100644 Documentation/devicetree/bindings/sound/option,gtm601.yaml diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt deleted file mode 100644 index efa32a486c4a..000000000000 --- a/Documentation/devicetree/bindings/sound/gtm601.txt +++ /dev/null @@ -1,19 +0,0 @@ -GTM601 UMTS modem audio interface CODEC - -This device has no configuration interface. The sample rate and channels are -based on the compatible string - "option,gtm601" = 8kHz mono - "broadmobi,bm818" = 48KHz stereo - -Required properties: - - - compatible : one of - "option,gtm601" - "broadmobi,bm818" - - -Example: - -codec: gtm601_codec { - compatible = "option,gtm601"; -}; diff --git a/Documentation/devicetree/bindings/sound/option,gtm601.yaml b/Documentation/devicetree/bindings/sound/option,gtm601.yaml new file mode 100644 index 000000000000..69c2ccc79dc5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/option,gtm601.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/option,gtm601.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GTM601 UMTS modem audio interface CODEC + +maintainers: + - kernel@puri.sm + +description: > + This device has no configuration interface. The sample rate and channels are + based on the compatible string + +properties: + compatible: + oneOf: + - items: # 48 kHz stereo + - const: broadmobi,bm818 + - const: option,gtm601 + - const: option,gtm601 # 8 kHz mono + + '#sound-dai-cells': + const: 0 + +required: + - compatible + +allOf: + - $ref: dai-common.yaml# + +additionalProperties: false + +examples: + - | + codec { + compatible = "option,gtm601"; + #sound-dai-cells = <0>; + }; -- cgit v1.2.3 From 785c00993dc4c4bb2f7b0f3a3f29c03a6f7aab2e Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 27 Jul 2023 09:43:15 +0800 Subject: platform/x86/amd/pmf: Fix unsigned comparison with less than zero The return value from the call to amd_pmf_get_pprof_modes() is int. However, the return value is being assigned to an unsigned char variable 'mode', so making 'mode' an int. silence the warning: ./drivers/platform/x86/amd/pmf/sps.c:183:5-9: WARNING: Unsigned expression compared with zero: mode < 0 Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5995 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230727014315.51375-1-yang.lee@linux.alibaba.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/sps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index ab69d517a36a..a70e67749be3 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -176,7 +176,8 @@ int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) { - u8 mode, flag = 0; + u8 flag = 0; + int mode; int src; mode = amd_pmf_get_pprof_modes(dev); -- cgit v1.2.3 From 1cd0302be5645420f73090aee26fa787287e1096 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 28 Jul 2023 12:13:45 +0100 Subject: ACPI: scan: Create platform device for CS35L56 The ACPI device CSC3556 is a Cirrus Logic CS35L56 mono amplifier which is used in multiples, and can be connected either to I2C or SPI. There will be multiple instances under the same Device() node. Add it to ignore_serial_bus_ids and handle it in the serial-multi-instantiate driver. There can be a 5th I2cSerialBusV2, but this is an alias address and doesn't represent a real device. Ignore this by having a dummy 5th entry in the serial-multi-instantiate instance list with the name of a non-existent driver, on the same pattern as done for bsg2150. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230728111345.7224-1-rf@opensource.cirrus.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/acpi/scan.c | 1 + drivers/platform/x86/serial-multi-instantiate.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5b145f1aaa1b..87e385542576 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1714,6 +1714,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) {"BSG1160", }, {"BSG2150", }, {"CSC3551", }, + {"CSC3556", }, {"INT33FE", }, {"INT3515", }, /* Non-conforming _HID for Cirrus Logic already released */ diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 2c2abf69f049..8158e3cf5d6d 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -329,6 +329,19 @@ static const struct smi_node cs35l41_hda = { .bus_type = SMI_AUTO_DETECT, }; +static const struct smi_node cs35l56_hda = { + .instances = { + { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 }, + { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 }, + { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 }, + { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 }, + /* a 5th entry is an alias address, not a real device */ + { "cs35l56-hda_dummy_dev" }, + {} + }, + .bus_type = SMI_AUTO_DETECT, +}; + /* * Note new device-ids must also be added to ignore_serial_bus_ids in * drivers/acpi/scan.c: acpi_device_enumeration_by_parent(). @@ -337,6 +350,7 @@ static const struct acpi_device_id smi_acpi_ids[] = { { "BSG1160", (unsigned long)&bsg1160_data }, { "BSG2150", (unsigned long)&bsg2150_data }, { "CSC3551", (unsigned long)&cs35l41_hda }, + { "CSC3556", (unsigned long)&cs35l56_hda }, { "INT3515", (unsigned long)&int3515_data }, /* Non-conforming _HID for Cirrus Logic already released */ { "CLSA0100", (unsigned long)&cs35l41_hda }, -- cgit v1.2.3 From 0169cc3f200cbd737a57592fc478b24ff3cec3c5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 11:47:02 +0100 Subject: ASoC: wm8960: Read initial MCLK rate from clock API When we have a MCLK provided by the clock API read the rate at startup and store it so that there's something set before the machine driver has done clocking configuration (eg, if it only configures clocking based on sample rate). Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230731-asoc-wm8960-clk-v1-1-69f9ffa2b10a@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index c2bd9ef41ebb..d4bc97088354 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1429,6 +1429,14 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) if (IS_ERR(wm8960->mclk)) { if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER) return -EPROBE_DEFER; + } else { + ret = clk_get_rate(wm8960->mclk); + if (ret >= 0) { + wm8960->freq_in = ret; + } else { + dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n", + ret); + } } wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); -- cgit v1.2.3 From 2bbc2df46e67be1a26b9c2b18a581b83e17ccb19 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 11:47:03 +0100 Subject: ASoC: wm8960: Make automatic the default clocking mode The wm8960 driver supports an automatic clocking mode which will use the MCLK directly where possible and fall back to the PLL if there is no suitable configuration directly using the MCLK. Clock 0 will be used by the generic cards when configuring things, currently this is a MCLK only mode but using AUTO mode would be more functional. Since the driver still prefers to use MCLK directly where possible there should be no negative impact on systems which are able to use MCLK directly. As far as I can see nothing is using the system clock as part of the ABI, the only reference I can see to a mode in a machine driver is the Freescale i.MX card which uses the automatic mode with an explicit in kernel call using the constant so will be unaffected. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230731-asoc-wm8960-clk-v1-2-69f9ffa2b10a@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h index 63ba6c03c488..e8ff33b188e9 100644 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -77,9 +77,9 @@ #define WM8960_SYSCLK_DIV_1 (0 << 1) #define WM8960_SYSCLK_DIV_2 (2 << 1) -#define WM8960_SYSCLK_MCLK (0 << 0) +#define WM8960_SYSCLK_AUTO (0 << 0) #define WM8960_SYSCLK_PLL (1 << 0) -#define WM8960_SYSCLK_AUTO (2 << 0) +#define WM8960_SYSCLK_MCLK (2 << 0) #define WM8960_DAC_DIV_1 (0 << 3) #define WM8960_DAC_DIV_1_5 (1 << 3) -- cgit v1.2.3 From 36eb986845a8ca87c1f7f91976fad53ee249ae8c Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 31 Jul 2023 18:34:19 +0800 Subject: ASoC: Intel: maxim-common: get codec number from ACPI table We implement a helper function to get number of codecs from ACPI subsystem instead of using quirk flag in machine driver. Also refactor module interface by adding max_98390_dai_link() function. On the sof_rt5682 machine driver side, we remove the quirk flag SOF_MAX98390_TWEETER_SPEAKER_PRESENT and use the new interface of max98390 to setup dai link. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731103419.2536036-2-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 170 ++++++++++++++++++------------ sound/soc/intel/boards/sof_maxim_common.h | 21 ++-- sound/soc/intel/boards/sof_rt5682.c | 37 +------ 3 files changed, 111 insertions(+), 117 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 112e89951da0..628b6d5d3ee4 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,18 @@ #include #include "sof_maxim_common.h" +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + #define MAX_98373_PIN_NAME 16 const struct snd_soc_dapm_route max_98373_dapm_routes[] = { @@ -168,17 +181,6 @@ static struct snd_soc_codec_conf max_98390_codec_conf[] = { .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), .name_prefix = "Left", }, -}; - -static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), - .name_prefix = "Left", - }, { .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), .name_prefix = "Tweeter Right", @@ -189,19 +191,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { }, }; -struct snd_soc_dai_link_component max_98390_components[] = { - { - .name = MAX_98390_DEV0_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, - { - .name = MAX_98390_DEV1_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, -}; -EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); - -struct snd_soc_dai_link_component max_98390_4spk_components[] = { +static struct snd_soc_dai_link_component max_98390_components[] = { { .name = MAX_98390_DEV0_NAME, .dai_name = MAX_98390_CODEC_DAI, @@ -219,62 +209,56 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = { .dai_name = MAX_98390_CODEC_DAI, }, }; -EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +static const struct { + unsigned int tx; + unsigned int rx; +} max_98390_tdm_mask[] = { + {.tx = 0x01, .rx = 0x3}, + {.tx = 0x02, .rx = 0x3}, + {.tx = 0x04, .rx = 0x3}, + {.tx = 0x08, .rx = 0x3}, +}; static int max_98390_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; - int i; + int i, ret; for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (i >= ARRAY_SIZE(max_98390_4spk_components)) { + if (i >= ARRAY_SIZE(max_98390_tdm_mask)) { dev_err(codec_dai->dev, "invalid codec index %d\n", i); return -ENODEV; } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { - /* DEV0 tdm slot configuration Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { - /* DEV1 tdm slot configuration Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); - } - - if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { - /* DEVi2 tdm slot configuration Tweeter Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { - /* DEV3 tdm slot configuration Tweeter Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx, + max_98390_tdm_mask[i].rx, 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; } } return 0; } -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +static int max_98390_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); int ret; - /* add regular speakers dapm route */ - ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, - ARRAY_SIZE(max_98390_dapm_routes)); - if (ret) { - dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); - return ret; - } - - /* add widgets/controls/dapm for tweeter speakers */ - if (acpi_dev_present("MX98390", "3", -1)) { + switch (num_codecs) { + case 4: + /* add widgets/controls/dapm for tweeter speakers */ ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, ARRAY_SIZE(max_98390_tt_dapm_widgets)); - if (ret) { - dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", + ret); /* Don't need to add routes if widget addition failed */ return ret; } @@ -282,33 +266,79 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, ARRAY_SIZE(max_98390_tt_kcontrols)); if (ret) { - dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n", + ret); return ret; } ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, ARRAY_SIZE(max_98390_tt_dapm_routes)); - if (ret) - dev_err(rtd->dev, - "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", + ret); + return ret; + } + + fallthrough; + case 2: + /* add regular speakers dapm route */ + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ARRAY_SIZE(max_98390_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "invalid codec number %d\n", num_codecs); + return -EINVAL; } + return ret; } -EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); -const struct snd_soc_ops max_98390_ops = { +static const struct snd_soc_ops max_98390_ops = { .hw_params = max_98390_hw_params, }; -EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + link->codecs = max_98390_components; + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; + } + + link->init = max_98390_init; + link->ops = &max_98390_ops; +} +EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) { - if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { - card->codec_conf = max_98390_4spk_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); - } else { - card->codec_conf = max_98390_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_codec_conf); + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + card->codec_conf = max_98390_codec_conf; + + switch (num_codecs) { + case 2: + case 4: + card->num_configs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; } } EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 7a8c53049e4d..a095b47b856b 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -27,18 +27,15 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); /* * Maxim MAX98390 */ -#define MAX_98390_CODEC_DAI "max98390-aif1" -#define MAX_98390_DEV0_NAME "i2c-MX98390:00" -#define MAX_98390_DEV1_NAME "i2c-MX98390:01" -#define MAX_98390_DEV2_NAME "i2c-MX98390:02" -#define MAX_98390_DEV3_NAME "i2c-MX98390:03" - -extern struct snd_soc_dai_link_component max_98390_components[2]; -extern struct snd_soc_dai_link_component max_98390_4spk_components[4]; -extern const struct snd_soc_ops max_98390_ops; - -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch); -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd); +#define MAX_98390_ACPI_HID "MX98390" +#define MAX_98390_CODEC_DAI "max98390-aif1" +#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00" +#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01" +#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02" +#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03" + +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card); /* * Maxim MAX98357A/MAX98360A diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index b4f07bdcf8b4..0af1e0c3a9db 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -59,7 +59,6 @@ #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) #define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) -#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) #define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27) @@ -195,23 +194,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_SSP_AMP(2) | SOF_RT5682_NUM_HDMIDEV(4)), }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), - DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_MAX98390_SPEAKER_AMP_PRESENT | - SOF_MAX98390_TWEETER_SPEAKER_PRESENT | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - - }, { .callback = sof_rt5682_quirk_cb, .matches = { @@ -850,17 +832,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, sof_rt1011_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & - SOF_MAX98390_TWEETER_SPEAKER_PRESENT) { - links[id].codecs = max_98390_4spk_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components); - } else { - links[id].codecs = max_98390_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_components); - } - links[id].init = max_98390_spk_codec_init; - links[id].ops = &max_98390_ops; - + max_98390_dai_link(dev, &links[id]); } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { links[id].codecs = &rt5650_components[1]; links[id].num_codecs = 1; @@ -1019,12 +991,7 @@ static int sof_audio_probe(struct platform_device *pdev) else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) sof_rt1015p_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT) - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_4spk_components)); - else - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_components)); + max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); } if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) -- cgit v1.2.3 From 175544ad48cbf56affeef2a679c6a4d4fb1e2881 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Fri, 28 Jul 2023 21:59:24 -0700 Subject: scsi: storvsc: Fix handling of virtual Fibre Channel timeouts Hyper-V provides the ability to connect Fibre Channel LUNs to the host system and present them in a guest VM as a SCSI device. I/O to the vFC device is handled by the storvsc driver. The storvsc driver includes a partial integration with the FC transport implemented in the generic portion of the Linux SCSI subsystem so that FC attributes can be displayed in /sys. However, the partial integration means that some aspects of vFC don't work properly. Unfortunately, a full and correct integration isn't practical because of limitations in what Hyper-V provides to the guest. In particular, in the context of Hyper-V storvsc, the FC transport timeout function fc_eh_timed_out() causes a kernel panic because it can't find the rport and dereferences a NULL pointer. The original patch that added the call from storvsc_eh_timed_out() to fc_eh_timed_out() is faulty in this regard. In many cases a timeout is due to a transient condition, so the situation can be improved by just continuing to wait like with other I/O requests issued by storvsc, and avoiding the guaranteed panic. For a permanent failure, continuing to wait may result in a hung thread instead of a panic, which again may be better. So fix the panic by removing the storvsc call to fc_eh_timed_out(). This allows storvsc to keep waiting for a response. The change has been tested by users who experienced a panic in fc_eh_timed_out() due to transient timeouts, and it solves their problem. In the future we may want to deprecate the vFC functionality in storvsc since it can't be fully fixed. But it has current users for whom it is working well enough, so it should probably stay for a while longer. Fixes: 3930d7309807 ("scsi: storvsc: use default I/O timeout handler for FC devices") Cc: stable@vger.kernel.org Signed-off-by: Michael Kelley Link: https://lore.kernel.org/r/1690606764-79669-1-git-send-email-mikelley@microsoft.com Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index f2823218670a..047ffaf7d42a 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1674,10 +1674,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) */ static enum scsi_timeout_action storvsc_eh_timed_out(struct scsi_cmnd *scmnd) { -#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) - if (scmnd->device->host->transportt == fc_transport_template) - return fc_eh_timed_out(scmnd); -#endif return SCSI_EH_RESET_TIMER; } -- cgit v1.2.3 From 5a43b07a87835660f91d88a4db11abfea8c523b7 Mon Sep 17 00:00:00 2001 From: Karan Tilak Kumar Date: Thu, 27 Jul 2023 12:39:19 -0700 Subject: scsi: fnic: Replace return codes in fnic_clean_pending_aborts() fnic_clean_pending_aborts() was returning a non-zero value irrespective of failure or success. This caused the caller of this function to assume that the device reset had failed, even though it would succeed in most cases. As a consequence, a successful device reset would escalate to host reset. Reviewed-by: Sesidhar Baddela Tested-by: Karan Tilak Kumar Signed-off-by: Karan Tilak Kumar Link: https://lore.kernel.org/r/20230727193919.2519-1-kartilak@cisco.com Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic.h | 2 +- drivers/scsi/fnic/fnic_scsi.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index d82de34f6fd7..e51e92f932fa 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -27,7 +27,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.54" +#define DRV_VERSION "1.6.0.55" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 26dbd347156e..be89ce96df46 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -2139,7 +2139,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, bool new_sc) { - int ret = SUCCESS; + int ret = 0; struct fnic_pending_aborts_iter_data iter_data = { .fnic = fnic, .lun_dev = lr_sc->device, @@ -2159,9 +2159,11 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, /* walk again to check, if IOs are still pending in fw */ if (fnic_is_abts_pending(fnic, lr_sc)) - ret = FAILED; + ret = 1; clean_pending_aborts_end: + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + "%s: exit status: %d\n", __func__, ret); return ret; } -- cgit v1.2.3 From 8366d1f1249a0d0bba41d0bd1298d63e5d34c7f7 Mon Sep 17 00:00:00 2001 From: Alexandra Diupina Date: Fri, 28 Jul 2023 15:35:21 +0300 Subject: scsi: 53c700: Check that command slot is not NULL Add a check for the command slot value to avoid dereferencing a NULL pointer. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Co-developed-by: Vladimir Telezhnikov Signed-off-by: Vladimir Telezhnikov Signed-off-by: Alexandra Diupina Link: https://lore.kernel.org/r/20230728123521.18293-1-adiupina@astralinux.ru Signed-off-by: Martin K. Petersen --- drivers/scsi/53c700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index e1e4f9d10887..857be0f3ae5b 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -1598,7 +1598,7 @@ NCR_700_intr(int irq, void *dev_id) printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); #endif resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; - } else if(dsp >= to32bit(&slot->pSG[0].ins) && + } else if (slot && dsp >= to32bit(&slot->pSG[0].ins) && dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); -- cgit v1.2.3 From 9426d3cef5000824e5f24f80ed5f42fb935f2488 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 24 Jul 2023 14:25:40 -0400 Subject: scsi: core: Fix legacy /proc parsing buffer overflow (lightly modified commit message mostly by Linus Torvalds) The parsing code for /proc/scsi/scsi is disgusting and broken. We should have just used 'sscanf()' or something simple like that, but the logic may actually predate our kernel sscanf library routine for all I know. It certainly predates both git and BK histories. And we can't change it to be something sane like that now, because the string matching at the start is done case-insensitively, and the separator parsing between numbers isn't done at all, so *any* separator will work, including a possible terminating NUL character. This interface is root-only, and entirely for legacy use, so there is absolutely no point in trying to tighten up the parsing. Because any separator has traditionally worked, it's entirely possible that people have used random characters rather than the suggested space. So don't bother to try to pretty it up, and let's just make a minimal patch that can be back-ported and we can forget about this whole sorry thing for another two decades. Just make it at least not read past the end of the supplied data. Link: https://lore.kernel.org/linux-scsi/b570f5fe-cb7c-863a-6ed9-f6774c219b88@cybernetics.com/ Cc: Linus Torvalds Cc: Martin K Petersen Cc: James Bottomley Cc: Willy Tarreau Cc: stable@kernel.org Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Tony Battersby Signed-off-by: Martin K Petersen --- drivers/scsi/scsi_proc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 4a6eb1741be0..41f23cd0bfb4 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -406,7 +406,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, size_t length, loff_t *ppos) { int host, channel, id, lun; - char *buffer, *p; + char *buffer, *end, *p; int err; if (!buf || length > PAGE_SIZE) @@ -421,10 +421,14 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, goto out; err = -EINVAL; - if (length < PAGE_SIZE) - buffer[length] = '\0'; - else if (buffer[PAGE_SIZE-1]) - goto out; + if (length < PAGE_SIZE) { + end = buffer + length; + *end = '\0'; + } else { + end = buffer + PAGE_SIZE - 1; + if (*end) + goto out; + } /* * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi @@ -433,10 +437,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, if (!strncmp("scsi add-single-device", buffer, 22)) { p = buffer + 23; - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p + 1, &p, 0); - id = simple_strtoul(p + 1, &p, 0); - lun = simple_strtoul(p + 1, &p, 0); + host = (p < end) ? simple_strtoul(p, &p, 0) : 0; + channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; + id = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; + lun = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; err = scsi_add_single_device(host, channel, id, lun); @@ -447,10 +451,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, } else if (!strncmp("scsi remove-single-device", buffer, 25)) { p = buffer + 26; - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p + 1, &p, 0); - id = simple_strtoul(p + 1, &p, 0); - lun = simple_strtoul(p + 1, &p, 0); + host = (p < end) ? simple_strtoul(p, &p, 0) : 0; + channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; + id = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; + lun = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0; err = scsi_remove_single_device(host, channel, id, lun); } -- cgit v1.2.3 From d4480c9bb9258db9ddf2e632f6ef81e96b41089c Mon Sep 17 00:00:00 2001 From: Martin Kohn Date: Thu, 27 Jul 2023 20:00:43 +0000 Subject: net: usb: qmi_wwan: add Quectel EM05GV2 Add support for Quectel EM05GV2 (G=global) with vendor ID 0x2c7c and product ID 0x030e Enabling DTR on this modem was necessary to ensure stable operation. Patch for usb: serial: option: is also in progress. T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2c7c ProdID=030e Rev= 3.18 S: Manufacturer=Quectel S: Product=Quectel EM05-G C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=89(I) Atr=03(Int.) MxPS= 8 Ivl=32ms E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Martin Kohn Link: https://lore.kernel.org/r/AM0PR04MB57648219DE893EE04FA6CC759701A@AM0PR04MB5764.eurprd04.prod.outlook.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 417f7ea1fffa..344af3c5c836 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1423,6 +1423,7 @@ static const struct usb_device_id products[] = { {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0195, 4)}, /* Quectel EG95 */ {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)}, /* Quectel EM05GV2 */ {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */ {QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/ -- cgit v1.2.3 From 55c1528f9b97ff3b7efad73e8f79627fc2efb298 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 28 Jul 2023 17:55:28 +0100 Subject: sfc: fix field-spanning memcpy in selftest Add a struct_group for the whole packet body so we can copy it in one go without triggering FORTIFY_SOURCE complaints. Fixes: cf60ed469629 ("sfc: use padding to fix alignment in loopback test") Fixes: 30c24dd87f3f ("sfc: siena: use padding to fix alignment in loopback test") Fixes: 1186c6b31ee1 ("sfc: falcon: use padding to fix alignment in loopback test") Reviewed-by: Andy Moreton Tested-by: Andy Moreton Signed-off-by: Edward Cree Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230728165528.59070-1-edward.cree@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/falcon/selftest.c | 23 +++++++++++++---------- drivers/net/ethernet/sfc/selftest.c | 23 +++++++++++++---------- drivers/net/ethernet/sfc/siena/selftest.c | 23 +++++++++++++---------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c index 9e5ce2a13787..cf1d67b6d86d 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.c +++ b/drivers/net/ethernet/sfc/falcon/selftest.c @@ -40,15 +40,16 @@ */ struct ef4_loopback_payload { char pad[2]; /* Ensures ip is 4-byte aligned */ - struct ethhdr header; - struct iphdr ip; - struct udphdr udp; - __be16 iteration; - char msg[64]; + struct_group_attr(packet, __packed, + struct ethhdr header; + struct iphdr ip; + struct udphdr udp; + __be16 iteration; + char msg[64]; + ); } __packed __aligned(4); -#define EF4_LOOPBACK_PAYLOAD_LEN (sizeof(struct ef4_loopback_payload) - \ - offsetof(struct ef4_loopback_payload, \ - header)) +#define EF4_LOOPBACK_PAYLOAD_LEN \ + sizeof_field(struct ef4_loopback_payload, packet) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -299,7 +300,7 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, payload = &state->payload; - memcpy(&received.header, buf_ptr, + memcpy(&received.packet, buf_ptr, min_t(int, pkt_len, EF4_LOOPBACK_PAYLOAD_LEN)); received.ip.saddr = payload->ip.saddr; if (state->offload_csum) @@ -370,7 +371,7 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload.header, EF4_LOOPBACK_PAYLOAD_LEN, + &state->payload.packet, EF4_LOOPBACK_PAYLOAD_LEN, 0); } #endif @@ -440,6 +441,8 @@ static int ef4_begin_loopback(struct ef4_tx_queue *tx_queue) payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); /* Strip off the leading padding */ skb_pull(skb, offsetof(struct ef4_loopback_payload, header)); + /* Strip off the trailing padding */ + skb_trim(skb, EF4_LOOPBACK_PAYLOAD_LEN); /* Ensure everything we've written is visible to the * interrupt handler. */ diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 96d856b9043c..19a0b8584afb 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -43,15 +43,16 @@ */ struct efx_loopback_payload { char pad[2]; /* Ensures ip is 4-byte aligned */ - struct ethhdr header; - struct iphdr ip; - struct udphdr udp; - __be16 iteration; - char msg[64]; + struct_group_attr(packet, __packed, + struct ethhdr header; + struct iphdr ip; + struct udphdr udp; + __be16 iteration; + char msg[64]; + ); } __packed __aligned(4); -#define EFX_LOOPBACK_PAYLOAD_LEN (sizeof(struct efx_loopback_payload) - \ - offsetof(struct efx_loopback_payload, \ - header)) +#define EFX_LOOPBACK_PAYLOAD_LEN \ + sizeof_field(struct efx_loopback_payload, packet) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -297,7 +298,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, payload = &state->payload; - memcpy(&received.header, buf_ptr, + memcpy(&received.packet, buf_ptr, min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); received.ip.saddr = payload->ip.saddr; if (state->offload_csum) @@ -368,7 +369,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload.header, EFX_LOOPBACK_PAYLOAD_LEN, + &state->payload.packet, EFX_LOOPBACK_PAYLOAD_LEN, 0); } #endif @@ -438,6 +439,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); /* Strip off the leading padding */ skb_pull(skb, offsetof(struct efx_loopback_payload, header)); + /* Strip off the trailing padding */ + skb_trim(skb, EFX_LOOPBACK_PAYLOAD_LEN); /* Ensure everything we've written is visible to the * interrupt handler. */ diff --git a/drivers/net/ethernet/sfc/siena/selftest.c b/drivers/net/ethernet/sfc/siena/selftest.c index 111ac17194a5..b55fd3346972 100644 --- a/drivers/net/ethernet/sfc/siena/selftest.c +++ b/drivers/net/ethernet/sfc/siena/selftest.c @@ -43,15 +43,16 @@ */ struct efx_loopback_payload { char pad[2]; /* Ensures ip is 4-byte aligned */ - struct ethhdr header; - struct iphdr ip; - struct udphdr udp; - __be16 iteration; - char msg[64]; + struct_group_attr(packet, __packed, + struct ethhdr header; + struct iphdr ip; + struct udphdr udp; + __be16 iteration; + char msg[64]; + ); } __packed __aligned(4); -#define EFX_LOOPBACK_PAYLOAD_LEN (sizeof(struct efx_loopback_payload) - \ - offsetof(struct efx_loopback_payload, \ - header)) +#define EFX_LOOPBACK_PAYLOAD_LEN \ + sizeof_field(struct efx_loopback_payload, packet) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -297,7 +298,7 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, payload = &state->payload; - memcpy(&received.header, buf_ptr, + memcpy(&received.packet, buf_ptr, min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); received.ip.saddr = payload->ip.saddr; if (state->offload_csum) @@ -368,7 +369,7 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload.header, EFX_LOOPBACK_PAYLOAD_LEN, + &state->payload.packet, EFX_LOOPBACK_PAYLOAD_LEN, 0); } #endif @@ -438,6 +439,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); /* Strip off the leading padding */ skb_pull(skb, offsetof(struct efx_loopback_payload, header)); + /* Strip off the trailing padding */ + skb_trim(skb, EFX_LOOPBACK_PAYLOAD_LEN); /* Ensure everything we've written is visible to the * interrupt handler. */ -- cgit v1.2.3 From 4b31fd4d77ffa430d0b74ba1885ea0a41594f202 Mon Sep 17 00:00:00 2001 From: Rafal Rogalski Date: Fri, 28 Jul 2023 10:12:43 -0700 Subject: ice: Fix RDMA VSI removal during queue rebuild During qdisc create/delete, it is necessary to rebuild the queue of VSIs. An error occurred because the VSIs created by RDMA were still active. Added check if RDMA is active. If yes, it disallows qdisc changes and writes a message in the system logs. Fixes: 348048e724a0 ("ice: Implement iidc operations") Signed-off-by: Rafal Rogalski Signed-off-by: Mateusz Palczewski Signed-off-by: Kamil Maziarz Tested-by: Bharathi Sreenivas Signed-off-by: Tony Nguyen Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230728171243.2446101-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f02d44455772..cf92c39467c8 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -8813,6 +8813,7 @@ ice_setup_tc(struct net_device *netdev, enum tc_setup_type type, { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_pf *pf = np->vsi->back; + bool locked = false; int err; switch (type) { @@ -8822,10 +8823,27 @@ ice_setup_tc(struct net_device *netdev, enum tc_setup_type type, ice_setup_tc_block_cb, np, np, true); case TC_SETUP_QDISC_MQPRIO: + if (pf->adev) { + mutex_lock(&pf->adev_mutex); + device_lock(&pf->adev->dev); + locked = true; + if (pf->adev->dev.driver) { + netdev_err(netdev, "Cannot change qdisc when RDMA is active\n"); + err = -EBUSY; + goto adev_unlock; + } + } + /* setup traffic classifier for receive side */ mutex_lock(&pf->tc_mutex); err = ice_setup_tc_mqprio_qdisc(netdev, type_data); mutex_unlock(&pf->tc_mutex); + +adev_unlock: + if (locked) { + device_unlock(&pf->adev->dev); + mutex_unlock(&pf->adev_mutex); + } return err; default: return -EOPNOTSUPP; -- cgit v1.2.3 From 37b61cda9c1606cd8b6445d900ca9dc03185e8b6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 28 Jul 2023 13:50:20 -0700 Subject: bnxt: don't handle XDP in netpoll Similarly to other recently fixed drivers make sure we don't try to access XDP or page pool APIs when NAPI budget is 0. NAPI budget of 0 may mean that we are in netpoll. This may result in running software IRQs in hard IRQ context, leading to deadlocks or crashes. To make sure bnapi->tx_pkts don't get wiped without handling the events, move clearing the field into the handler itself. Remember to clear tx_pkts after reset (bnxt_enable_napi()) as it's technically possible that netpoll will accumulate some tx_pkts and then a reset will happen, leaving tx_pkts out of sync with reality. Fixes: 322b87ca55f2 ("bnxt_en: add page_pool support") Reviewed-by: Andy Gospodarek Reviewed-by: Michael Chan Link: https://lore.kernel.org/r/20230728205020.2784844-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 +++++++++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 8 +++++++- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h | 2 +- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e5b54e6025be..06b238bef9dd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -633,12 +633,13 @@ tx_kick_pending: return NETDEV_TX_OK; } -static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) +static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txr->txq_index); u16 cons = txr->tx_cons; struct pci_dev *pdev = bp->pdev; + int nr_pkts = bnapi->tx_pkts; int i; unsigned int tx_bytes = 0; @@ -688,6 +689,7 @@ next_tx_int: dev_kfree_skb_any(skb); } + bnapi->tx_pkts = 0; WRITE_ONCE(txr->tx_cons, cons); __netif_txq_completed_wake(txq, nr_pkts, tx_bytes, @@ -2569,12 +2571,11 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, return rx_pkts; } -static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi) +static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi, + int budget) { - if (bnapi->tx_pkts) { - bnapi->tx_int(bp, bnapi, bnapi->tx_pkts); - bnapi->tx_pkts = 0; - } + if (bnapi->tx_pkts) + bnapi->tx_int(bp, bnapi, budget); if ((bnapi->events & BNXT_RX_EVENT) && !(bnapi->in_reset)) { struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; @@ -2603,7 +2604,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, */ bnxt_db_cq(bp, &cpr->cp_db, cpr->cp_raw_cons); - __bnxt_poll_work_done(bp, bnapi); + __bnxt_poll_work_done(bp, bnapi, budget); return rx_pkts; } @@ -2734,7 +2735,7 @@ static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) } static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, - u64 dbr_type) + u64 dbr_type, int budget) { struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; int i; @@ -2750,7 +2751,7 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, cpr2->had_work_done = 0; } } - __bnxt_poll_work_done(bp, bnapi); + __bnxt_poll_work_done(bp, bnapi, budget); } static int bnxt_poll_p5(struct napi_struct *napi, int budget) @@ -2780,7 +2781,8 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) if (cpr->has_more_work) break; - __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL); + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL, + budget); cpr->cp_raw_cons = raw_cons; if (napi_complete_done(napi, work_done)) BNXT_DB_NQ_ARM_P5(&cpr->cp_db, @@ -2810,7 +2812,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) } raw_cons = NEXT_RAW_CMP(raw_cons); } - __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ); + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, budget); if (raw_cons != cpr->cp_raw_cons) { cpr->cp_raw_cons = raw_cons; BNXT_DB_NQ_P5(&cpr->cp_db, raw_cons); @@ -9429,6 +9431,8 @@ static void bnxt_enable_napi(struct bnxt *bp) cpr->sw_stats.rx.rx_resets++; bnapi->in_reset = false; + bnapi->tx_pkts = 0; + if (bnapi->rx_ring) { INIT_WORK(&cpr->dim.work, bnxt_dim_work); cpr->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 080e73496066..bb95c3dc5270 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1005,7 +1005,7 @@ struct bnxt_napi { struct bnxt_tx_ring_info *tx_ring; void (*tx_int)(struct bnxt *, struct bnxt_napi *, - int); + int budget); int tx_pkts; u8 events; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 4efa5fe6972b..7f2f9a317d47 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -125,16 +125,20 @@ static void __bnxt_xmit_xdp_redirect(struct bnxt *bp, dma_unmap_len_set(tx_buf, len, 0); } -void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) +void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; bool rx_doorbell_needed = false; + int nr_pkts = bnapi->tx_pkts; struct bnxt_sw_tx_bd *tx_buf; u16 tx_cons = txr->tx_cons; u16 last_tx_cons = tx_cons; int i, j, frags; + if (!budget) + return; + for (i = 0; i < nr_pkts; i++) { tx_buf = &txr->tx_buf_ring[tx_cons]; @@ -161,6 +165,8 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) } tx_cons = NEXT_TX(tx_cons); } + + bnapi->tx_pkts = 0; WRITE_ONCE(txr->tx_cons, tx_cons); if (rx_doorbell_needed) { tx_buf = &txr->tx_buf_ring[last_tx_cons]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h index ea430d6961df..5e412c5655ba 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h @@ -16,7 +16,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, struct bnxt_tx_ring_info *txr, dma_addr_t mapping, u32 len, struct xdp_buff *xdp); -void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts); +void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget); bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, struct xdp_buff xdp, struct page *page, u8 **data_ptr, unsigned int *len, u8 *event); -- cgit v1.2.3 From 611e1b016c7beceec5ae82ac62d4a7ca224c8f9d Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Sat, 29 Jul 2023 17:15:16 +0200 Subject: octeon_ep: initialize mbox mutexes The two mbox-related mutexes are destroyed in octep_ctrl_mbox_uninit(), but the corresponding mutex_init calls were missing. A "DEBUG_LOCKS_WARN_ON(lock->magic != lock)" warning was emitted with CONFIG_DEBUG_MUTEXES on. Initialize the two mutexes in octep_ctrl_mbox_init(). Fixes: 577f0d1b1c5f ("octeon_ep: add separate mailbox command and response queues") Signed-off-by: Michal Schmidt Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230729151516.24153-1-mschmidt@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c index 035ead7935c7..dab61cc1acb5 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c @@ -98,6 +98,9 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox) writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem)); + mutex_init(&mbox->h2fq_lock); + mutex_init(&mbox->f2hq_lock); + mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem)); mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem); mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem); -- cgit v1.2.3 From 390e7066db29b985c5142513955797c1166b623a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:41 -0500 Subject: ASoC: SOF: sof-client-probes-ipc4: add checks to prevent static analysis warnings make KCFLAGS='-fanalyzer' sound/soc/sof/ reports several NULL pointer dereference paths. sof_ipc4_probe_get_module_info() can return a NULL value, but it's only tested in the init state. Static analyzers cannot know the probe state machine and hence flags a potential issue for all calls of that function. Squelch these errors by adding the same check consistently. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes-ipc4.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index ea21ef176c42..c56a85854d92 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -146,6 +146,9 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev) struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); struct sof_ipc4_msg msg; + if (!mentry) + return -ENODEV; + msg.primary = mentry->id; msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE); msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); @@ -197,6 +200,9 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev, struct sof_ipc4_msg msg; int i, ret; + if (!mentry) + return -ENODEV; + /* The sof_probe_point_desc and sof_ipc4_probe_point structs * are of same size and even the integers are the same in the * same order, and similar meaning, but since there is no @@ -247,6 +253,9 @@ static int ipc4_probes_points_remove(struct sof_client_dev *cdev, u32 *probe_point_ids; int i, ret; + if (!mentry) + return -ENODEV; + probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids), GFP_KERNEL); if (!probe_point_ids) -- cgit v1.2.3 From e44222c213678d6ef646d72cbb9a2eda52f6dc22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:42 -0500 Subject: ASoC: SOF: ipc3: add checks to prevent static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/sof/ reports an issue with memcpy: sound/soc/sof/ipc3.c: In function ‘ipc3_wait_tx_done’: sound/soc/sof/ipc3.c:309:33: error: use of NULL ‘reply_data’ where non-null expected [CWE-476] [-Werror=analyzer-null-argument] 309 | memcpy(reply_data, msg->reply_data, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 310 | msg->reply_size); The finding is legit with this call: return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx), NULL, 0, false); Static analysis has no way of knowing that the reply will be zero-sized. Add a check to only do the memcpy if the reply size is not zero and the destination pointer is not NULL. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 2c5aac31e8b0..09834205b119 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -312,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) } else { if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS)) ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); - if (msg->reply_size) + if (reply_data && msg->reply_size) /* copy the data returned from DSP */ memcpy(reply_data, msg->reply_data, msg->reply_size); -- cgit v1.2.3 From 55cb3dc271d81f1982c949a2ac483a6daf613b92 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:43 -0500 Subject: ASoC: SOF: topology: simplify code to prevent static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/sof/intel/ reports a possible NULL pointer dereference. sound/soc/sof/topology.c:1136:21: error: dereference of NULL ‘w’ [CWE-476] [-Werror=analyzer-null-dereference] 1136 | strcmp(w->sname, rtd->dai_link->stream_name)) The code is rather confusing and can be simplified to make static analysis happy. No functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 698129dccc7d..3866dd3cba69 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1117,10 +1117,11 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, { struct snd_soc_card *card = scomp->card; struct snd_soc_pcm_runtime *rtd; + const char *sname = w->sname; struct snd_soc_dai *cpu_dai; int i, stream; - if (!w->sname) + if (!sname) return; if (w->id == snd_soc_dapm_dai_out) @@ -1133,7 +1134,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || - strcmp(w->sname, rtd->dai_link->stream_name)) + strcmp(sname, rtd->dai_link->stream_name)) continue; for_each_rtd_cpu_dais(rtd, i, cpu_dai) -- cgit v1.2.3 From e302f8d9f799af57a61a7456451c28f2647e9751 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:44 -0500 Subject: ASoC: SOF: imx: remove error checks on NULL ipc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit imx_dsp_get_data() can return NULL, but the value is not checked before being usd, leading to static analysis warnings. sound/soc/sof/imx/imx8.c:85:32: error: dereference of NULL ‘0’ [CWE-476] [-Werror=analyzer-null-dereference] 85 | spin_lock_irqsave(&priv->sdev->ipc_lock, flags); | ~~~~^~~~~~ It appears this is not really a possible problem, so remove those checks. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/linux/firmware/imx/dsp.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/firmware/imx/dsp.h b/include/linux/firmware/imx/dsp.h index 4f7895a3b73c..1f176a2683fe 100644 --- a/include/linux/firmware/imx/dsp.h +++ b/include/linux/firmware/imx/dsp.h @@ -37,17 +37,11 @@ struct imx_dsp_ipc { static inline void imx_dsp_set_data(struct imx_dsp_ipc *ipc, void *data) { - if (!ipc) - return; - ipc->private_data = data; } static inline void *imx_dsp_get_data(struct imx_dsp_ipc *ipc) { - if (!ipc) - return NULL; - return ipc->private_data; } -- cgit v1.2.3 From 8cf5286216dcfb942f0e4d7c23ebe06c2ebc1bed Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:45 -0500 Subject: ASoC: SOF: mediatek: remove error checks on NULL ipc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mtk_adsp_ipc_get_data() can return NULL, but the value is not checked before being used, leading to static analysis warnings. sound/soc/sof/mediatek/mt8195/mt8195.c:90:32: error: dereference of NULL ‘0’ [CWE-476] [-Werror=analyzer-null-dereference] 90 | spin_lock_irqsave(&priv->sdev->ipc_lock, flags); | ~~~~^~~~~~ It appears this is not really a possible problem, so remove those checks. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/linux/firmware/mediatek/mtk-adsp-ipc.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h index 28fd313340b8..5b1d16fa3f56 100644 --- a/include/linux/firmware/mediatek/mtk-adsp-ipc.h +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -46,17 +46,11 @@ struct mtk_adsp_ipc { static inline void mtk_adsp_ipc_set_data(struct mtk_adsp_ipc *ipc, void *data) { - if (!ipc) - return; - ipc->private_data = data; } static inline void *mtk_adsp_ipc_get_data(struct mtk_adsp_ipc *ipc) { - if (!ipc) - return NULL; - return ipc->private_data; } -- cgit v1.2.3 From 64778b022e629b8ffa97d23a9adbf670aa3bb1d8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:46 -0500 Subject: ASoC: Intel: bdw_rt286: add checks to avoid static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snd_soc_card_get_codec_dai() can return NULL, but that value is not checked for, leading to false-positive static analysis warnings sound/soc/intel/boards/bdw_rt286.c:190:16: error: dereference of NULL ‘codec_dai’ [CWE-476] [-Werror=analyzer-null-dereference] 190 | return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ‘card_suspend_pre’: event 1 | | 190 | return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) dereference of NULL ‘codec_dai’ This NULL dereference cannot happen, the codec-dai "rt286-aif1" must exists otherwise the card would not be created. Static analysis cannot know that however so we might as well squelch this report. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw_rt286.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index b7687a93a923..036579331d8f 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -187,6 +187,9 @@ static int card_suspend_pre(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); } @@ -194,6 +197,9 @@ static int card_resume_post(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL); } -- cgit v1.2.3 From 71d76768fbe72aa70dd61d5714a5579dc4ca61cb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:47 -0500 Subject: ASoC: Intel: atom: remove static analysis false positive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/intel/atom/ reports a possible NULL pointer dereference. sound/soc/intel/atom/sst/sst_stream.c:221:40: error: dereference of NULL ‘block’ [CWE-476] [-Werror=analyzer-null-dereference] 221 | unsigned char *r = block->data; This is a false-positive, the GCC analyzer generated that report by considering if (bytes->block) as true in some cases and false in others. We can simplify the code and use a local variable so that static analysis does not try to look for cases where bytes->block can be modified concurrently. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 862a19ae5429..288221db7323 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, u32 length; int pvt_id, ret = 0; struct sst_block *block = NULL; + u8 bytes_block = bytes->block; dev_dbg(sst_drv_ctx->dev, "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", - bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, + bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id, bytes->pipe_id, bytes->len); if (sst_create_ipc_msg(&msg, true)) @@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, pvt_id = sst_assign_pvt_id(sst_drv_ctx); sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, bytes->task_id, 1, pvt_id); - msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; + msg->mrfld_header.p.header_high.part.res_rqd = bytes_block; length = bytes->len; msg->mrfld_header.p.header_low_payload = length; dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); - if (bytes->block) { + if (bytes_block) { block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); if (block == NULL) { kfree(msg); @@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", msg->mrfld_header.p.header_low_payload); - if (bytes->block) { + if (bytes_block) { ret = sst_wait_timeout(sst_drv_ctx, block); if (ret) { dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); @@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, * copy the reply and send back * we need to update only sz and payload */ - if (bytes->block) { + if (bytes_block) { unsigned char *r = block->data; dev_dbg(sst_drv_ctx->dev, "read back %d bytes", @@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, memcpy(bytes->bytes, r, bytes->len); } } - if (bytes->block) + if (bytes_block) sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); -- cgit v1.2.3 From 871861f6ad6d43b49caade3f42b9d40ca1413e79 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:48 -0500 Subject: ASoC: amd: acp5x-mach:add checks to avoid static analysis warnings snd_soc_card_get_codec_dai() can return NULL, but that value is not checked for, leading to static analysis warnings. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/vangogh/acp5x-mach.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 125a8e93478d..eda464545866 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -170,6 +170,9 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME); int ret, bclk; + if (!dai) + return -EINVAL; + ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN); if (ret < 0) dev_err(card->dev, "can't set FS clock %d\n", ret); -- cgit v1.2.3 From e63e2810edd229e320249dc85c20c22f4894919e Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 31 Jul 2023 16:42:35 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for rt711-sdca-sdw at link 0 in RPL match table Adding RT711 sdca SDW codec support with SDW0 link for RPL RVP platforms Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 302a08018572..99dc76c99f0d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -308,6 +308,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {} }; +static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr rplp_crb[] = { { .mask = BIT(2), @@ -413,6 +422,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", }, + { + .link_mask = 0x1, /* link0 required */ + .links = rpl_sdca_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", + }, { .link_mask = 0x4, /* link2 required */ .links = rplp_crb, -- cgit v1.2.3 From 26d9726f667e18134bfc77a3e4e0da7518a8b180 Mon Sep 17 00:00:00 2001 From: Terry Cheong Date: Mon, 31 Jul 2023 16:42:36 -0500 Subject: ASoC: Intel: sof_rt5682: add RPL support for MAX98357A speaker Adding support back to RPL devices that lost audio after the RPL/ADL split. The hardware configuration is: SSP0: 10EC5682/RTL5682 codec SSP2: MAX98357A amplifier Reviewed-by: Bard Liao Signed-off-by: Terry Cheong Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 8 ++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0af1e0c3a9db..a5af6ae79933 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -1163,6 +1163,14 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { .name = "rpl_mx98360_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 99dc76c99f0d..4eefdb2dd45c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -331,6 +331,11 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { .num_codecs = 1, .codecs = {"MX98360A"}, @@ -347,6 +352,13 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { }; struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { + { + .comp_ids = &rpl_rt5682_hp, + .drv_name = "rpl_mx98357_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_max98357a_amp, + .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg", + }, { .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_mx98360_rt5682", -- cgit v1.2.3 From f3c37847c704c5d398fa6808c77e4f7c997c0abb Mon Sep 17 00:00:00 2001 From: apoorv Date: Mon, 31 Jul 2023 16:42:37 -0500 Subject: ASoC: Intel: sof_rt5682 add support for HDMI_In capture Adding support for 2 streams of HDMI-In capture via I2S with rt5682s codec variant Reviewed-by: CBM Reviewed-by: Bard Liao Signed-off-by: apoorv Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 47 +++++++++++++++++++++++ sound/soc/intel/common/soc-acpi-intel-adl-match.c | 7 ++++ 2 files changed, 54 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index a5af6ae79933..fae091b9b55c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -62,6 +62,11 @@ #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) #define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27) +/* HDMI capture*/ +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27 +#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) +#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -670,6 +675,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i, id = 0; + int hdmi_id_offset = 0; links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -891,6 +897,34 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_cpus = 1; } + /* HDMI-In SSP */ + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) { + unsigned long hdmi_in_ssp = (sof_rt5682_quirk & + SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + int port = 0; + + for_each_set_bit(port, &hdmi_in_ssp, 32) { + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + return links; devm_err: return NULL; @@ -997,6 +1031,11 @@ static int sof_audio_probe(struct platform_device *pdev) if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) sof_audio_card_rt5682.num_links++; + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) + sof_audio_card_rt5682.num_links += + hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num, ctx->idisp_codec); if (!dai_links) @@ -1163,6 +1202,14 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "adl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(1) | + SOF_RT5682_NUM_HDMIDEV(3) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + }, { .name = "rpl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index bcd66e0094b4..8e995edf4c10 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -568,6 +568,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .quirk_data = &adl_max98390_amp, .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg", }, + { + .comp_ids = &adl_rt5682_rt5682s_hp, + .drv_name = "adl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_lt6911_hdmi, + .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &adl_rt5682_rt5682s_hp, .drv_name = "adl_rt5682", -- cgit v1.2.3 From a14aded9299187bb17ef90700eb2cf1120ef5885 Mon Sep 17 00:00:00 2001 From: Uday M Bhat Date: Mon, 31 Jul 2023 16:42:38 -0500 Subject: ASoC: Intel: sof_sdw: Update BT offload config for soundwire config For soundwire config, SSP1 is used for BT offload. This is enabled in sof_sdw_quirk_table Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Uday M Bhat Signed-off-by: Jairaj Arava Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dbee8c98ff01..b811446be4cd 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -467,7 +467,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC), + .driver_data = (void *)(SOF_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, /* LunarLake devices */ { -- cgit v1.2.3 From 4b68ce6912fd87b1743eb2e66aeba81cae2067fe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:39 -0500 Subject: ASoC: Intel: sof_sdw: reorder SoundWire codecs in Kconfig No functionality change, just sort Realtek codecs using increasing part IDs. Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 1fe830af2b84..141fba0f8c70 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -671,12 +671,12 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT711_SDCA_SDW select SND_SOC_RT712_SDCA_SDW select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT1316_SDW select SND_SOC_RT1318_SDW - select SND_SOC_RT715_SDW - select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW select SND_SOC_DMIC -- cgit v1.2.3 From 3390d4ed823e716618095c16ad6792f33cc66190 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:40 -0500 Subject: ASoC: Intel: sof_sdw: allow mockup amplifier to provide feedback The capture setting are missing and preventing topologies with feedback from loading. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b811446be4cd..7e43be46cfa8 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -942,10 +942,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .version_id = 0, .dais = { { - .direction = {true, false}, + .direction = {true, true}, .dai_name = "sdw-mockup-aif1", .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = NULL, }, }, -- cgit v1.2.3 From 616bee2c06ca1cd24631ae0db1b4cba1d6b9ad25 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 31 Jul 2023 16:42:41 -0500 Subject: ASoC: Intel: sof_sdw: rename link_id to be_id The link_id parameter in create_sdw_dailink is actually the BE link id. Rename it to be_id to be consistent with the caller and less confusion. No functionality change. Reviewed-by: Rander Wang Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 7e43be46cfa8..acaedd3b2224 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1354,7 +1354,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, - int codec_count, int *link_id, + int codec_count, int *be_id, int *codec_conf_index, bool *ignore_pch_dmic, bool append_dai_type, @@ -1433,9 +1433,9 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (!codec_info->dais[dai_index].direction[stream]) continue; - *link_id = codec_info->dais[dai_index].dailink[stream]; - if (*link_id < 0) { - dev_err(dev, "Invalid dailink id %d\n", *link_id); + *be_id = codec_info->dais[dai_index].dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); return -EINVAL; } @@ -1492,7 +1492,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *link_index, (*link_id)++, name, + init_dai_link(dev, dai_links + *link_index, (*be_id)++, name, playback, capture, cpus + *cpu_id, cpu_dai_num, codecs, codec_num, -- cgit v1.2.3 From 0cc85f2bfbcb84754ee6cd43a6fb9953f18cd2dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:42 -0500 Subject: ASoC: Intel: sof_sdw: add support for SKU 0AFE Yet another missing configuration, with the standard configuration link0: rt711-sdca link 1 and 2: rt1316-sdca link3: rt714-sdca Link: https://github.com/thesofproject/sof/issues/7799 Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index acaedd3b2224..ffb0cd0700c4 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -307,6 +307,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_FOUR_SPK), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_SDW_FOUR_SPK), + }, { .callback = sof_sdw_quirk_cb, .matches = { -- cgit v1.2.3 From 1d1062382b1807679e9001d79704112525576057 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:43 -0500 Subject: ASoC: intel: sof_sdw: Use consistent variable naming for links The driver makes extensive use of both ACPI link and ASoC DAI link structs, often referring to both with the variable name link. Make the code a little easier to follow by consistently using adr_link for the ACPI bits and dai_links for the ASoC bits. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 118 ++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ffb0cd0700c4..6f65f45bded6 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1021,10 +1021,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links, +static int get_sdw_dailink_info(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, int *sdw_be_num, int *sdw_cpu_dai_num) { - const struct snd_soc_acpi_link_adr *link; bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; int i; @@ -1034,27 +1034,27 @@ static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_li *sdw_cpu_dai_num = 0; *sdw_be_num = 0; - if (!links) + if (!adr_link) return -EINVAL; for (i = 0; i < SDW_MAX_GROUPS; i++) group_visited[i] = false; - for (link = links; link->num_adr; link++) { + for (; adr_link->num_adr; adr_link++) { const struct snd_soc_acpi_endpoint *endpoint; struct sof_sdw_codec_info *codec_info; int codec_index; int stream; u64 adr; - for (i = 0; i < link->num_adr; i++) { - adr = link->adr_d[i].adr; + for (i = 0; i < adr_link->num_adr; i++) { + adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; codec_info = &codec_info_list[codec_index]; - endpoint = link->adr_d[i].endpoints; + endpoint = adr_link->adr_d[i].endpoints; for (j = 0; j < codec_info->dai_num; j++) { /* count DAI number for playback and capture */ @@ -1102,7 +1102,7 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links dai_links->ops = ops; } -static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, +static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int sdw_version, unsigned int mfg_id, unsigned int part_id, @@ -1112,7 +1112,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, { int i; - for (i = 0; i < link->num_adr; i++) { + for (i = 0; i < adr_link->num_adr; i++) { unsigned int sdw1_version, mfg1_id, part1_id, class1_id; u64 adr; @@ -1120,7 +1120,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, if (i == index_in_link) continue; - adr = link->adr_d[i].adr; + adr = adr_link->adr_d[i].adr; sdw1_version = SDW_VERSION(adr); mfg1_id = SDW_MFG_ID(adr); @@ -1138,7 +1138,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, } static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, int offset, struct snd_soc_codec_conf *codec_conf, @@ -1151,19 +1151,19 @@ static int create_codec_dai_name(struct device *dev, int i; /* sanity check */ - if (*codec_conf_index + link->num_adr - adr_index > codec_count) { + if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { dev_err(dev, "codec_conf: out-of-bounds access requested\n"); return -EINVAL; } - for (i = adr_index; i < link->num_adr; i++) { + for (i = adr_index; i < adr_link->num_adr; i++) { unsigned int sdw_version, unique_id, mfg_id; unsigned int link_id, part_id, class_id; int codec_index, comp_index; char *codec_str; u64 adr; - adr = link->adr_d[i].adr; + adr = adr_link->adr_d[i].adr; sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); @@ -1173,7 +1173,7 @@ static int create_codec_dai_name(struct device *dev, class_id = SDW_CLASS_ID(adr); comp_index = i - adr_index + offset; - if (is_unique_device(link, sdw_version, mfg_id, part_id, + if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, class_id, i)) { codec_str = "sdw:%01x:%04x:%04x:%02x"; codec[comp_index].name = @@ -1204,7 +1204,7 @@ static int create_codec_dai_name(struct device *dev, codec_info_list[codec_index].dais[dai_index].dai_name; codec_conf[*codec_conf_index].dlc = codec[comp_index]; - codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix; + codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; ++*codec_conf_index; } @@ -1213,7 +1213,7 @@ static int create_codec_dai_name(struct device *dev, } static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link *dai_links, bool playback, int group_id, int adr_index, int dai_index) { @@ -1224,34 +1224,35 @@ static int set_codec_init_func(struct snd_soc_card *card, * Initialize the codec. If codec is part of an aggregated * group (group_id>0), initialize all codecs belonging to * same group. - * The first link should start with link->adr_d[adr_index] + * The first link should start with adr_link->adr_d[adr_index] * because that is the device that we want to initialize and * we should end immediately if it is not aggregated (group_id=0) */ - for ( ; i < link->num_adr; i++) { + for ( ; i < adr_link->num_adr; i++) { int codec_index; - codec_index = find_codec_info_part(link->adr_d[i].adr); + codec_index = find_codec_info_part(adr_link->adr_d[i].adr); if (codec_index < 0) return codec_index; /* The group_id is > 0 iff the codec is aggregated */ - if (link->adr_d[i].endpoints->group_id != group_id) + if (adr_link->adr_d[i].endpoints->group_id != group_id) continue; if (codec_info_list[codec_index].dais[dai_index].init) codec_info_list[codec_index].dais[dai_index].init(card, - link, + adr_link, dai_links, &codec_info_list[codec_index], playback); if (!group_id) return 0; } + i = 0; - link++; - } while (link->mask); + adr_link++; + } while (adr_link->mask); return 0; } @@ -1361,7 +1362,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, int codec_count, int *be_id, @@ -1371,7 +1372,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int adr_index, int dai_index) { - const struct snd_soc_acpi_link_adr *link_next; + const struct snd_soc_acpi_link_adr *adr_link_next; struct snd_soc_dai_link_component *codecs; struct sof_sdw_codec_info *codec_info; int cpu_dai_id[SDW_MAX_CPU_DAIS]; @@ -1385,7 +1386,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int ret; int k; - ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, + ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, &group_id, group_generated, adr_index); if (ret) return ret; @@ -1395,20 +1396,20 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -ENOMEM; /* generate codec name on different links in the same group */ - for (link_next = link; link_next && link_next->num_adr && - i < cpu_dai_num; link_next++) { + for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && + i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; - endpoints = link_next->adr_d->endpoints; + endpoints = adr_link_next->adr_d->endpoints; if (group_id && (!endpoints->aggregated || endpoints->group_id != group_id)) continue; /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(link_next->mask) - 1) + if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, link_next, codecs, codec_idx, + ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_idx, codec_conf, codec_count, codec_conf_index, adr_index, dai_index); if (ret < 0) @@ -1416,11 +1417,11 @@ static int create_sdw_dailink(struct snd_soc_card *card, /* check next link to create codec dai in the processed group */ i++; - codec_idx += link_next->num_adr; + codec_idx += adr_link_next->num_adr; } /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(link->adr_d[adr_index].adr); + codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); if (codec_index < 0) return codec_index; codec_info = &codec_info_list[codec_index]; @@ -1516,7 +1517,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; - ret = set_codec_init_func(card, link, dai_links + (*link_index)++, + ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { dev_err(dev, "failed to init codec %d", codec_index); @@ -1589,7 +1590,7 @@ static int sof_card_dai_links_create(struct device *dev, int codec_conf_index = 0; bool group_generated[SDW_MAX_GROUPS]; int ssp_codec_index, ssp_mask; - struct snd_soc_dai_link *links; + struct snd_soc_dai_link *dai_links; int num_links, link_index = 0; char *name, *cpu_name; int total_cpu_dai_num; @@ -1650,14 +1651,14 @@ static int sof_card_dai_links_create(struct device *dev, /* allocate BE dailinks */ num_links = comp_num + sdw_be_num; - links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL); + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); /* allocated CPU DAIs */ total_cpu_dai_num = comp_num + sdw_cpu_dai_num; cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); - if (!links || !cpus) + if (!dai_links || !cpus) return -ENOMEM; /* SDW */ @@ -1731,9 +1732,9 @@ out: return codec_index; for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num, - sdw_cpu_dai_num, cpus, adr_link, - &cpu_id, group_generated, + ret = create_sdw_dailink(card, dev, &link_index, dai_links, + sdw_be_num, sdw_cpu_dai_num, cpus, + adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); @@ -1785,13 +1786,13 @@ SSP: playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, playback, capture, cpus + cpu_id, 1, ssp_components, 1, NULL, info->ops); - ret = info->dais[0].init(card, NULL, links + link_index, info, 0); + ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); if (ret < 0) return ret; @@ -1806,7 +1807,7 @@ DMIC: goto HDMI; } cpus[cpu_id].dai_name = "DMIC01 Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic01", + init_dai_link(dev, dai_links + link_index, be_id, "dmic01", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1814,7 +1815,7 @@ DMIC: INC_ID(be_id, cpu_id, link_index); cpus[cpu_id].dai_name = "DMIC16k Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic16k", + init_dai_link(dev, dai_links + link_index, be_id, "dmic16k", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1857,7 +1858,7 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 0, // HDMI only supports playback cpus + cpu_id, 1, idisp_components + i, 1, @@ -1878,11 +1879,11 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, 1, 1, - cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1, + cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); } - card->dai_link = links; + card->dai_link = dai_links; card->num_links = num_links; card->codec_conf = codec_conf; @@ -1925,15 +1926,15 @@ static struct snd_soc_card card_sof_sdw = { static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, const char *dai_name) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int i; int j; - for_each_card_prelinks(card, i, link) { - for (j = 0; j < link->num_codecs; j++) { + for_each_card_prelinks(card, i, dai_link) { + for (j = 0; j < dai_link->num_codecs; j++) { /* Check each codec in a link */ - if (!strcmp(link->codecs[j].dai_name, dai_name)) - return link; + if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) + return dai_link; } } return NULL; @@ -1941,7 +1942,7 @@ static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card static void mc_dailink_exit_loop(struct snd_soc_card *card) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int ret; int i, j; @@ -1954,10 +1955,11 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) * We don't need to call .exit function if there is no matched * dai link found. */ - link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name); - if (link) { + dai_link = mc_find_codec_dai_used(card, + codec_info_list[i].dais[j].dai_name); + if (dai_link) { /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, link); + ret = codec_info_list[i].dais[j].exit(card, dai_link); if (ret) dev_warn(card->dev, "codec exit failed %d\n", -- cgit v1.2.3 From 4fc16d21b7abb969935162d8b01fba21496cf513 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:44 -0500 Subject: ASoC: intel: sof_sdw: Rename codec_idx to codec_dlc_index Having two local variables called codec_idx and codec_index, that refer to different things is a little confusing. Rename codec_idx to codec_dlc_index to indicate it points into the dai_link_component array. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6f65f45bded6..0743bf04aa88 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1378,7 +1378,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int cpu_dai_id[SDW_MAX_CPU_DAIS]; int cpu_dai_num, cpu_dai_index; unsigned int group_id; - int codec_idx = 0; + int codec_dlc_index = 0; int codec_index; int codec_num; int stream; @@ -1409,7 +1409,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_idx, + ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_dlc_index, codec_conf, codec_count, codec_conf_index, adr_index, dai_index); if (ret < 0) @@ -1417,7 +1417,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, /* check next link to create codec dai in the processed group */ i++; - codec_idx += adr_link_next->num_adr; + codec_dlc_index += adr_link_next->num_adr; } /* find codec info to create BE DAI */ -- cgit v1.2.3 From 08f62f6291bae6e0cc5f3f50e4e1043e6a270e80 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:45 -0500 Subject: ASoC: intel: sof_sdw: Remove some extra line breaks Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0743bf04aa88..4f7ef83c21c5 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -523,7 +523,6 @@ int sdw_prepare(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -543,7 +542,6 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -631,7 +629,6 @@ int sdw_hw_free(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -1107,8 +1104,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int mfg_id, unsigned int part_id, unsigned int class_id, - int index_in_link - ) + int index_in_link) { int i; @@ -1232,7 +1228,6 @@ static int set_codec_init_func(struct snd_soc_card *card, int codec_index; codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) return codec_index; -- cgit v1.2.3 From 18c45cb362fcd6918548a4e11128304aa634acf3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:46 -0500 Subject: ASoC: intel: sof_sdw: Use a module device table A module device table is generally preferred over hard coding a MODULE_ALIAS. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 4f7ef83c21c5..6b55bcdccccc 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -2045,6 +2045,12 @@ static void mc_remove(struct platform_device *pdev) mc_dailink_exit_loop(card); } +static const struct platform_device_id mc_id_table[] = { + { "sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + static struct platform_driver sof_sdw_driver = { .driver = { .name = "sof_sdw", @@ -2052,6 +2058,7 @@ static struct platform_driver sof_sdw_driver = { }, .probe = mc_probe, .remove_new = mc_remove, + .id_table = mc_id_table, }; module_platform_driver(sof_sdw_driver); @@ -2061,6 +2068,5 @@ MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_sdw"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -- cgit v1.2.3 From 31a54f78ad1d294432d63e9f72db08dc14cca432 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:47 -0500 Subject: ASoC: intel: sof_sdw: Simplify find_codec_info_acpi Use a return rather than a break and an additional range check. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6b55bcdccccc..d3222f40d798 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1003,14 +1003,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) return -EINVAL; for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, - ACPI_ID_LEN)) - break; - - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) + return i; - return i; + return -EINVAL; } /* -- cgit v1.2.3 From fad1a9eff67d34b6f90cf4d1d2f1dc2632dfeeb4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:48 -0500 Subject: ASoC: intel: sof_sdw: Constify parameter to find_codec_part_info The address passed to find_codec_part_info should be const. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d3222f40d798..fc67029b3a64 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -974,7 +974,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, }; -static inline int find_codec_info_part(u64 adr) +static inline int find_codec_info_part(const u64 adr) { unsigned int part_id, sdw_version; int i; -- cgit v1.2.3 From 855e69f4ff9d726df4c8c47e7b40934fdb49d9c5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:49 -0500 Subject: ASoC: intel: sof_sdw: Minor tidy up of mc_probe Shuffle things around to group operations a little more, and consistently use card->dev. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index fc67029b3a64..d4f2711b6f26 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1964,34 +1964,34 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) static int mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = &card_sof_sdw; - struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); struct mc_private *ctx; int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry\n"); + card->dev = &pdev->dev; + + dev_dbg(card->dev, "Entry\n"); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + snd_soc_card_set_drvdata(card, ctx); + dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(&pdev->dev); - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); + log_quirks(card->dev); - mach = pdev->dev.platform_data; - ret = sof_card_dai_links_create(&pdev->dev, mach, - card); + ret = sof_card_dai_links_create(card->dev, mach, card); if (ret < 0) return ret; @@ -2022,7 +2022,7 @@ static int mc_probe(struct platform_device *pdev) card->long_name = sdw_card_long_name; /* Register the card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); mc_dailink_exit_loop(card); -- cgit v1.2.3 From febac07b4c69242d7870944457c3a1158ab97bdc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:50 -0500 Subject: ASoC: intel: sof_sdw: Remove redundant parameters in dai creation Pull the device and mach struct out of the card rather than explicitly passing to sof_card_dai_links_create. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d4f2711b6f26..dc5337ea75da 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1348,8 +1348,7 @@ static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_m static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int create_sdw_dailink(struct snd_soc_card *card, - struct device *dev, int *link_index, +static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, @@ -1363,6 +1362,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int adr_index, int dai_index) { + struct device *dev = card->dev; const struct snd_soc_acpi_link_adr *adr_link_next; struct snd_soc_dai_link_component *codecs; struct sof_sdw_codec_info *codec_info; @@ -1563,10 +1563,10 @@ static int sof_card_codec_conf_alloc(struct device *dev, return 0; } -static int sof_card_dai_links_create(struct device *dev, - struct snd_soc_acpi_mach *mach, - struct snd_soc_card *card) +static int sof_card_dai_links_create(struct snd_soc_card *card) { + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link_component *idisp_components; @@ -1723,7 +1723,7 @@ out: return codec_index; for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - ret = create_sdw_dailink(card, dev, &link_index, dai_links, + ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, @@ -1991,7 +1991,7 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); - ret = sof_card_dai_links_create(card->dev, mach, card); + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; -- cgit v1.2.3 From 8673e68b594684fac53398ec5783a6c8469a07a1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:51 -0500 Subject: ASoC: intel: sof_sdw: Move amp_num initialisation to mc_probe The amp_num member of the info struct is zeroed at the start of sof_card_dai_links_create, but then summed in mc_probe after sof_card_dai_links_create is called. It is a little clearer to hoist the initialisation out of sof_card_dai_links_create so it is on the same level as the summation. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dc5337ea75da..1a60965439dd 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1599,10 +1599,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (ret < 0) return ret; - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - codec_info_list[i].amp_num = 0; - if (mach_params->codec_mask & IDISP_CODEC_MASK) { ctx->idisp_codec = true; @@ -1991,6 +1987,10 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + codec_info_list[i].amp_num = 0; + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; -- cgit v1.2.3 From 656dd91a3a1ca27a02d9a79d1720b2ca40d272cf Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 31 Jul 2023 16:42:52 -0500 Subject: ASoC: Intel: sof_sdw: break earlier when a adr link contains different codecs create_codec_dai_name() is used to create codec component's information in different adr links. We can and should break before we do anything. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1a60965439dd..846ba8e1515c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1157,6 +1157,15 @@ static int create_codec_dai_name(struct device *dev, adr = adr_link->adr_d[i].adr; + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; + if (_codec_index != -1 && codec_index != _codec_index) { + dev_dbg(dev, "Different devices on the same sdw link\n"); + break; + } + _codec_index = codec_index; + sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); unique_id = SDW_UNIQUE_ID(adr); @@ -1183,15 +1192,6 @@ static int create_codec_dai_name(struct device *dev, if (!codec[comp_index].name) return -ENOMEM; - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; - codec[comp_index].dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; -- cgit v1.2.3 From 009582008182bc0a2956d245fd0362e036f31dfe Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:53 -0500 Subject: ASoC: intel: sof_sdw: Allow direct specification of CODEC name Add support for MFD based CODEC drivers, by allowing the CODEC name to not be the SoundWire device directly. Signed-off-by: Charles Keepax Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 +++++- sound/soc/intel/boards/sof_sdw_common.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 846ba8e1515c..e6faed2b99b2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1174,7 +1174,11 @@ static int create_codec_dai_name(struct device *dev, class_id = SDW_CLASS_ID(adr); comp_index = i - adr_index + offset; - if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, + if (codec_info_list[codec_index].codec_name) { + codec[comp_index].name = + devm_kstrdup(dev, codec_info_list[codec_index].codec_name, + GFP_KERNEL); + } else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, class_id, i)) { codec_str = "sdw:%01x:%04x:%04x:%02x"; codec[comp_index].name = diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 37402170d5f9..fe234b98eb64 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -80,6 +80,7 @@ struct sof_sdw_dai_info { struct sof_sdw_codec_info { const int part_id; const int version_id; + const char *codec_name; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool ignore_pch_dmic; -- cgit v1.2.3 From 4754e29c779fe2a2677ba62896daf4bf980602a1 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 31 Jul 2023 16:42:54 -0500 Subject: ASoC: Intel: sof_sdw: add cs35l56 codec info Add cs35l56 support in sof_sdw machine driver. Reviewed-by: Rander Wang Signed-off-by: Chao Song Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/sof_sdw.c | 13 +++++++++ sound/soc/intel/boards/sof_sdw_common.h | 6 +++++ sound/soc/intel/boards/sof_sdw_cs_amp.c | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/boards/sof_sdw_cs_amp.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 141fba0f8c70..0ae6eecc8851 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -679,6 +679,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT1318_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW + select SND_SOC_CS35L56_SDW select SND_SOC_DMIC select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_SOF_MAXIM_COMMON diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 931415d9cf6f..a570b5b40f22 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -42,7 +42,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ sof_sdw_rt712_sdca.o sof_sdw_rt715.o \ sof_sdw_rt715_sdca.o sof_sdw_dmic.o \ - sof_sdw_cs42l42.o \ + sof_sdw_cs42l42.o sof_sdw_cs_amp.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e6faed2b99b2..5dbfcd88ab3c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -903,6 +903,19 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, .dai_num = 1, }, + { + .part_id = 0x3556, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs35l56-sdw1", + .dai_type = SOF_SDW_DAI_TYPE_AMP, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, + .init = sof_sdw_cs_amp_init, + }, + }, + .dai_num = 1, + }, { .part_id = 0x4242, .dais = { diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index fe234b98eb64..2f4fe6bc3d5d 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -206,4 +206,10 @@ int sof_sdw_cs42l42_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback); +/* CS AMP support */ +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); #endif diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c new file mode 100644 index 000000000000..98f6546f484b --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Intel Corporation + +/* + * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver + */ + +#include +#include +#include +#include +#include "sof_sdw_common.h" + +#define CODEC_NAME_SIZE 8 + +static int cs_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + const char *dai_name = rtd->dai_link->codecs->dai_name; + struct snd_soc_card *card = rtd->card; + char codec_name[CODEC_NAME_SIZE]; + + snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:%s", + card->components, codec_name); + if (!card->components) + return -ENOMEM; + + return 0; +} + + +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* Count amp number and do init on playback link only. */ + if (!playback) + return 0; + + info->amp_num++; + dai_links->init = cs_spk_init; + + return 0; +} -- cgit v1.2.3 From 98a7a1143f83289a84cba6dab60a4531cc4dfae2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:55 -0500 Subject: ASoC: intel: sof_sdw: Clean up DAI link counting The counting of each of the types of DAI link is a bit messy with things added onto an intermediate variable as it goes along. Re-order things a little to keep the order consistent with the rest of the function and simplify the process down to a variable for each type of DAI and then sum them at the end. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 61 +++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 5dbfcd88ab3c..dc6ea21b3341 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1584,12 +1584,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); - int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; + int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link_component *idisp_components; struct snd_soc_dai_link_component *ssp_components; - struct snd_soc_acpi_mach_params *mach_params; - const struct snd_soc_acpi_link_adr *adr_link; + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; @@ -1606,26 +1606,19 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int i, j, be_id = 0; int codec_index; int cpu_id = 0; - int comp_num; int ret; - mach_params = &mach->mach_params; - /* allocate codec conf, will be populated when dailinks are created */ ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count); if (ret < 0) return ret; - if (mach_params->codec_mask & IDISP_CODEC_MASK) { - ctx->idisp_codec = true; - - if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) - hdmi_num = SOF_TGL_HDMI_COUNT; - else - hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + ret = get_sdw_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num); + if (ret < 0) { + dev_err(dev, "failed to get sdw link info %d\n", ret); + return ret; } - ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* * on generic tgl platform, I2S or sdw mode is supported * based on board rework. A ACPI device is registered in @@ -1633,36 +1626,40 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) * Here check ACPI ID to confirm I2S is supported. */ ssp_codec_index = find_codec_info_acpi(mach->id); - ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0; - comp_num = hdmi_num + ssp_num; + if (ssp_codec_index >= 0) { + ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); + ssp_num = hweight_long(ssp_mask); + } - ret = get_sdw_dailink_info(dev, mach_params->links, - &sdw_be_num, &sdw_cpu_dai_num); - if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d", ret); - return ret; + if (mach_params->codec_mask & IDISP_CODEC_MASK) { + ctx->idisp_codec = true; + + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; } /* enable dmic01 & dmic16k */ - dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; - comp_num += dmic_num; + if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) + dmic_num = 2; if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - comp_num++; + bt_num = 1; - dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, - dmic_num, ctx->idisp_codec ? hdmi_num : 0); + dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", + sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num); /* allocate BE dailinks */ - num_links = comp_num + sdw_be_num; + num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) + return -ENOMEM; /* allocated CPU DAIs */ - total_cpu_dai_num = comp_num + sdw_cpu_dai_num; - cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), - GFP_KERNEL); - - if (!dai_links || !cpus) + total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num; + cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + if (!cpus) return -ENOMEM; /* SDW */ -- cgit v1.2.3 From a386162e7dc2c8bc1be2777b1c6d41156f69b210 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:56 -0500 Subject: ASoC: intel: sof_sdw: Merge codec_conf_alloc into dailink_info Rename get_sdw_dailink_info to simply get_dailink_info and have it also return the number of codecs present. Then hoist the allocation of the codec conf structure up into sof_card_dai_links_create. This saves an extra loop through the adr_link array, allows us to get rid of sof_card_codec_conf_alloc and makes the allocation more explicit. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-23-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 75 ++++++++++++---------------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dc6ea21b3341..25644eff5251 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1027,9 +1027,9 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - int *sdw_be_num, int *sdw_cpu_dai_num) +static int get_dailink_info(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num) { bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; @@ -1058,8 +1058,17 @@ static int get_sdw_dailink_info(struct device *dev, codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; + codec_info = &codec_info_list[codec_index]; + *codecs_num += codec_info->dai_num; + + if (!adr_link->adr_d[i].name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_link->adr_d[i].adr); + return -EINVAL; + } + endpoint = adr_link->adr_d[i].endpoints; for (j = 0; j < codec_info->dai_num; j++) { @@ -1540,46 +1549,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, #define IDISP_CODEC_MASK 0x4 -static int sof_card_codec_conf_alloc(struct device *dev, - struct snd_soc_acpi_mach_params *mach_params, - struct snd_soc_codec_conf **codec_conf, - int *codec_conf_count) -{ - const struct snd_soc_acpi_link_adr *adr_link; - struct snd_soc_codec_conf *c_conf; - int num_codecs = 0; - int codec_index; - int i; - - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - - /* generate DAI links by each sdw link */ - for (; adr_link->num_adr; adr_link++) { - for (i = 0; i < adr_link->num_adr; i++) { - if (!adr_link->adr_d[i].name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_link->adr_d[i].adr); - return -EINVAL; - } - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; - num_codecs += codec_info_list[codec_index].dai_num; - } - } - - c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL); - if (!c_conf) - return -ENOMEM; - - *codec_conf = c_conf; - *codec_conf_count = num_codecs; - - return 0; -} - static int sof_card_dai_links_create(struct snd_soc_card *card) { struct device *dev = card->dev; @@ -1594,7 +1563,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; bool ignore_pch_dmic = false; - int codec_conf_count; + int codec_conf_num = 0; int codec_conf_index = 0; bool group_generated[SDW_MAX_GROUPS]; int ssp_codec_index, ssp_mask; @@ -1608,12 +1577,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int cpu_id = 0; int ret; - /* allocate codec conf, will be populated when dailinks are created */ - ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count); - if (ret < 0) - return ret; - - ret = get_sdw_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num); + ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num, + &codec_conf_num); if (ret < 0) { dev_err(dev, "failed to get sdw link info %d\n", ret); return ret; @@ -1662,6 +1627,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!cpus) return -ENOMEM; + /* allocate codec conf, will be populated when dailinks are created */ + codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), + GFP_KERNEL); + if (!codec_conf) + return -ENOMEM; + /* SDW */ if (!sdw_be_num) goto SSP; @@ -1736,7 +1707,7 @@ out: ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, - codec_conf, codec_conf_count, + codec_conf, codec_conf_num, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); if (ret < 0) { @@ -1888,7 +1859,7 @@ HDMI: card->num_links = num_links; card->codec_conf = codec_conf; - card->num_configs = codec_conf_count; + card->num_configs = codec_conf_num; return 0; } -- cgit v1.2.3 From a60ed3b738705dbcb4afce9a24af00e2671edf19 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:57 -0500 Subject: ASoC: intel: sof_sdw: Move group_generated logic Hoist the handling logic for group_generated up to the sof_card_dai_links_create level. This avoids the need to pass the array through multiple levels of functions. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-24-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 25644eff5251..fd27e211211b 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1291,7 +1291,7 @@ static int set_codec_init_func(struct snd_soc_card *card, static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, struct device *dev, int *cpu_dai_id, int *cpu_dai_num, int *codec_num, unsigned int *group_id, - bool *group_generated, int adr_index) + int adr_index) { const struct snd_soc_acpi_adr_device *adr_d; const struct snd_soc_acpi_link_adr *adr_next; @@ -1351,11 +1351,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, } } - /* - * indicate CPU DAIs for this group have been generated - * to avoid generating CPU DAIs for this group again. - */ - group_generated[*group_id] = true; *cpu_dai_num = index; return 0; @@ -1379,8 +1374,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, const struct snd_soc_acpi_link_adr *adr_link, - int *cpu_id, bool *group_generated, - struct snd_soc_codec_conf *codec_conf, + int *cpu_id, struct snd_soc_codec_conf *codec_conf, int codec_count, int *be_id, int *codec_conf_index, bool *ignore_pch_dmic, @@ -1404,7 +1398,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int k; ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, group_generated, adr_index); + &group_id, adr_index); if (ret) return ret; @@ -1559,13 +1553,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_dai_link_component *ssp_components; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; + bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; bool ignore_pch_dmic = false; int codec_conf_num = 0; int codec_conf_index = 0; - bool group_generated[SDW_MAX_GROUPS]; + bool group_generated[SDW_MAX_GROUPS] = { }; int ssp_codec_index, ssp_mask; struct snd_soc_dai_link *dai_links; int num_links, link_index = 0; @@ -1641,14 +1636,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!adr_link) return -EINVAL; - /* - * SoundWire Slaves aggregated in the same group may be - * located on different hardware links. Clear array to indicate - * CPU DAIs for this group have not been generated. - */ - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_generated[i] = false; - for (i = 0; i < SDW_MAX_LINKS; i++) sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; @@ -1706,7 +1693,7 @@ out: for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, - adr_link, &cpu_id, group_generated, + adr_link, &cpu_id, codec_conf, codec_conf_num, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); @@ -1715,6 +1702,9 @@ out: return ret; } } + + if (aggregation && endpoint->aggregated) + group_generated[endpoint->group_id] = true; } } -- cgit v1.2.3 From 799d9933ba47d9b679637fa17454ed81ac353f52 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:37 -0500 Subject: ASoC: SOF: Intel: start simplify the signature of link_slaves_found() Start removing Intel-specific arguments to make that function usable by other SOC vendors. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 64bebe1a72bb..6d9fafb58581 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1433,13 +1433,11 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) /* Check if all Slaves defined on the link can be found */ -static bool link_slaves_found(struct snd_sof_dev *sdev, +static bool link_slaves_found(struct device *dev, const struct snd_soc_acpi_link_adr *link, - struct sdw_intel_ctx *sdw) + struct sdw_intel_slave_id *ids, + int num_slaves) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct sdw_intel_slave_id *ids = sdw->ids; - int num_slaves = sdw->num_slaves; unsigned int part_id, link_id, unique_id, mfg_id, version; int i, j, k; @@ -1487,19 +1485,16 @@ static bool link_slaves_found(struct snd_sof_dev *sdev, unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || ids[j].id.unique_id == unique_id) { - dev_dbg(bus->dev, "found %x at link %d\n", - part_id, link_id); + dev_dbg(dev, "found %x at link %d\n", part_id, link_id); break; } } else { - dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n", + dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", part_id, reported_part_count, expected_part_count, link_id); } } if (j == num_slaves) { - dev_dbg(bus->dev, - "Slave %x not found\n", - part_id); + dev_dbg(dev, "Slave %x not found\n", part_id); return false; } } @@ -1549,7 +1544,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * Try next machine if any expected Slaves * are not found on this link. */ - if (!link_slaves_found(sdev, link, hdev->sdw)) + if (!link_slaves_found(sdev->dev, link, hdev->sdw->ids, hdev->sdw->num_slaves)) break; } /* Found if all Slaves are checked */ -- cgit v1.2.3 From bb29a33c4b4da9c11e021b9a257ae2944ccaff01 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:38 -0500 Subject: ASoC: soc-acpi: move link_slaves_found() Move existing function in common library to make sure the code can be reused by other SoC vendors. No functionality change outside of the move and added prefix. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/linux/soundwire/sdw.h | 5 +++ include/linux/soundwire/sdw_intel.h | 7 +--- include/sound/soc-acpi.h | 6 +++ sound/soc/soc-acpi.c | 73 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.c | 76 ++----------------------------------- 5 files changed, 88 insertions(+), 79 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f523ceabd059..f248f9a6cd55 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -482,6 +482,11 @@ struct sdw_slave_id { __u8 sdw_version:4; }; +struct sdw_extended_slave_id { + int link_id; + struct sdw_slave_id id; +}; + /* * Helper macros to extract the MIPI-defined IDs * diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 11fc88fb0d78..fa67fad4ef51 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -264,11 +264,6 @@ struct sdw_intel_link_dev; */ #define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3) -struct sdw_intel_slave_id { - int link_id; - struct sdw_slave_id id; -}; - struct hdac_bus; /** @@ -298,7 +293,7 @@ struct sdw_intel_ctx { int num_slaves; acpi_handle handle; struct sdw_intel_link_dev **ldev; - struct sdw_intel_slave_id *ids; + struct sdw_extended_slave_id *ids; struct list_head link_list; struct mutex shim_lock; /* lock for access to shared SHIM registers */ u32 shim_mask; diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 528279056b3a..630bf7367fe6 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -9,6 +9,7 @@ #include #include #include +#include struct snd_soc_acpi_package_context { char *name; /* package name */ @@ -208,4 +209,9 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev) !strncmp(dev->parent->driver->name, "sof-audio-acpi", strlen("sof-audio-acpi")); } +bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, + const struct snd_soc_acpi_link_adr *link, + struct sdw_extended_slave_id *ids, + int num_slaves); + #endif diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 142476f1396f..9319e9b2a033 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -125,5 +125,78 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) } EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); +#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ + SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) + +/* Check if all Slaves defined on the link can be found */ +bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, + const struct snd_soc_acpi_link_adr *link, + struct sdw_extended_slave_id *ids, + int num_slaves) +{ + unsigned int part_id, link_id, unique_id, mfg_id, version; + int i, j, k; + + for (i = 0; i < link->num_adr; i++) { + u64 adr = link->adr_d[i].adr; + int reported_part_count = 0; + + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + link_id = SDW_DISCO_LINK_ID(adr); + version = SDW_VERSION(adr); + + for (j = 0; j < num_slaves; j++) { + /* find out how many identical parts were reported on that link */ + if (ids[j].link_id == link_id && + ids[j].id.part_id == part_id && + ids[j].id.mfg_id == mfg_id && + ids[j].id.sdw_version == version) + reported_part_count++; + } + + for (j = 0; j < num_slaves; j++) { + int expected_part_count = 0; + + if (ids[j].link_id != link_id || + ids[j].id.part_id != part_id || + ids[j].id.mfg_id != mfg_id || + ids[j].id.sdw_version != version) + continue; + + /* find out how many identical parts are expected */ + for (k = 0; k < link->num_adr; k++) { + u64 adr2 = link->adr_d[k].adr; + + if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) + expected_part_count++; + } + + if (reported_part_count == expected_part_count) { + /* + * we have to check unique id + * if there is more than one + * Slave on the link + */ + unique_id = SDW_UNIQUE_ID(adr); + if (reported_part_count == 1 || + ids[j].id.unique_id == unique_id) { + dev_dbg(dev, "found %x at link %d\n", part_id, link_id); + break; + } + } else { + dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", + part_id, reported_part_count, expected_part_count, link_id); + } + } + if (j == num_slaves) { + dev_dbg(dev, "Slave %x not found\n", part_id); + return false; + } + } + return true; +} +EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ALSA SoC ACPI module"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6d9fafb58581..a77c0a52dcad 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1429,78 +1429,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) -#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ - SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) - -/* Check if all Slaves defined on the link can be found */ -static bool link_slaves_found(struct device *dev, - const struct snd_soc_acpi_link_adr *link, - struct sdw_intel_slave_id *ids, - int num_slaves) -{ - unsigned int part_id, link_id, unique_id, mfg_id, version; - int i, j, k; - - for (i = 0; i < link->num_adr; i++) { - u64 adr = link->adr_d[i].adr; - int reported_part_count = 0; - - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - link_id = SDW_DISCO_LINK_ID(adr); - version = SDW_VERSION(adr); - - for (j = 0; j < num_slaves; j++) { - /* find out how many identical parts were reported on that link */ - if (ids[j].link_id == link_id && - ids[j].id.part_id == part_id && - ids[j].id.mfg_id == mfg_id && - ids[j].id.sdw_version == version) - reported_part_count++; - } - - for (j = 0; j < num_slaves; j++) { - int expected_part_count = 0; - - if (ids[j].link_id != link_id || - ids[j].id.part_id != part_id || - ids[j].id.mfg_id != mfg_id || - ids[j].id.sdw_version != version) - continue; - - /* find out how many identical parts are expected */ - for (k = 0; k < link->num_adr; k++) { - u64 adr2 = link->adr_d[k].adr; - - if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) - expected_part_count++; - } - - if (reported_part_count == expected_part_count) { - /* - * we have to check unique id - * if there is more than one - * Slave on the link - */ - unique_id = SDW_UNIQUE_ID(adr); - if (reported_part_count == 1 || - ids[j].id.unique_id == unique_id) { - dev_dbg(dev, "found %x at link %d\n", part_id, link_id); - break; - } - } else { - dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", - part_id, reported_part_count, expected_part_count, link_id); - } - } - if (j == num_slaves) { - dev_dbg(dev, "Slave %x not found\n", part_id); - return false; - } - } - return true; -} - static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -1544,7 +1472,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * Try next machine if any expected Slaves * are not found on this link. */ - if (!link_slaves_found(sdev->dev, link, hdev->sdw->ids, hdev->sdw->num_slaves)) + if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, + hdev->sdw->ids, + hdev->sdw->num_slaves)) break; } /* Found if all Slaves are checked */ -- cgit v1.2.3 From cf35ab3d58c65a924ef8caf5c40e5849d4aa253e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:39 -0500 Subject: ASoC: soc-acpi: improve log messagesin link_slaves_found() use 'part_id' to follow MIPI/SoundWire wording and use more consistent %#x format. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 9319e9b2a033..6d693b2ad5a3 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -181,16 +181,16 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || ids[j].id.unique_id == unique_id) { - dev_dbg(dev, "found %x at link %d\n", part_id, link_id); + dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); break; } } else { - dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", + dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n", part_id, reported_part_count, expected_part_count, link_id); } } if (j == num_slaves) { - dev_dbg(dev, "Slave %x not found\n", part_id); + dev_dbg(dev, "Slave part_id %#x not found\n", part_id); return false; } } -- cgit v1.2.3 From ed19c4a9b1024c4069d3d9f4daa3eb26a622069d Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 31 Jul 2023 16:32:40 -0500 Subject: ASoC: SOF: ipc3: update dai_link_fixup for SOF_DAI_MEDIATEK_AFE For MediaTek AFE, DAI DMA can support different bitwidths compared to the BE DAI. Therefore, it is preferable to obtain the BE frame format from the DAI_CONFIG. Reviewed-by: Yaochun Hung Reviewed-by: Daniel Baluta Signed-off-by: Trevor Wu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731213242.434594-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-pcm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 304faf6425ab..cb58ee8c158a 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -309,6 +309,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = private->dai_config->afe.channels; channels->max = private->dai_config->afe.channels; + snd_mask_none(fmt); + + switch (private->dai_config->afe.format) { + case SOF_IPC_FRAME_S16_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case SOF_IPC_FRAME_S24_4LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + break; + case SOF_IPC_FRAME_S32_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(component->dev, "Not available format!\n"); + return -EINVAL; + } + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); -- cgit v1.2.3 From 8dc97ccf94c73c62344a270986b837d02fb77c0f Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Mon, 31 Jul 2023 16:32:41 -0500 Subject: ASoC: SOF: Deprecate invalid enums in IPC3 The switch component was never completed and sat half empty for over 3 years. It was recently deleted. For modern components this would require not change in the kernel but since this was a legacy allocation from the enum days of IPC3 we should mark the respective enum as deprecated. The splitter component was never even got a source file in the firmware. Therefore also delete it since this is not needed. Reviewed-by: Bard Liao Signed-off-by: Curtis Malainey Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731213242.434594-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/topology.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 88560281d420..906e2f327ad2 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -26,9 +26,9 @@ enum sof_comp_type { SOF_COMP_MIXER, SOF_COMP_MUX, SOF_COMP_SRC, - SOF_COMP_SPLITTER, + SOF_COMP_DEPRECATED0, /* Formerly SOF_COMP_SPLITTER */ SOF_COMP_TONE, - SOF_COMP_SWITCH, + SOF_COMP_DEPRECATED1, /* Formerly SOF_COMP_SWITCH */ SOF_COMP_BUFFER, SOF_COMP_EQ_IIR, SOF_COMP_EQ_FIR, -- cgit v1.2.3 From 640a604585aa30f93e39b17d4d6ba69fcb1e66c9 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Sat, 29 Jul 2023 17:51:06 +0800 Subject: bpf, cpumap: Make sure kthread is running before map update returns The following warning was reported when running stress-mode enabled xdp_redirect_cpu with some RT threads: ------------[ cut here ]------------ WARNING: CPU: 4 PID: 65 at kernel/bpf/cpumap.c:135 CPU: 4 PID: 65 Comm: kworker/4:1 Not tainted 6.5.0-rc2+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) Workqueue: events cpu_map_kthread_stop RIP: 0010:put_cpu_map_entry+0xda/0x220 ...... Call Trace: ? show_regs+0x65/0x70 ? __warn+0xa5/0x240 ...... ? put_cpu_map_entry+0xda/0x220 cpu_map_kthread_stop+0x41/0x60 process_one_work+0x6b0/0xb80 worker_thread+0x96/0x720 kthread+0x1a5/0x1f0 ret_from_fork+0x3a/0x70 ret_from_fork_asm+0x1b/0x30 The root cause is the same as commit 436901649731 ("bpf: cpumap: Fix memory leak in cpu_map_update_elem"). The kthread is stopped prematurely by kthread_stop() in cpu_map_kthread_stop(), and kthread() doesn't call cpu_map_kthread_run() at all but XDP program has already queued some frames or skbs into ptr_ring. So when __cpu_map_ring_cleanup() checks the ptr_ring, it will find it was not emptied and report a warning. An alternative fix is to use __cpu_map_ring_cleanup() to drop these pending frames or skbs when kthread_stop() returns -EINTR, but it may confuse the user, because these frames or skbs have been handled correctly by XDP program. So instead of dropping these frames or skbs, just make sure the per-cpu kthread is running before __cpu_map_entry_alloc() returns. After apply the fix, the error handle for kthread_stop() will be unnecessary because it will always return 0, so just remove it. Fixes: 6710e1126934 ("bpf: introduce new bpf cpu map type BPF_MAP_TYPE_CPUMAP") Signed-off-by: Hou Tao Reviewed-by: Pu Lehui Acked-by: Jesper Dangaard Brouer Link: https://lore.kernel.org/r/20230729095107.1722450-2-houtao@huaweicloud.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/cpumap.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index 6ae02be7a48e..7eeb20025164 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,7 @@ struct bpf_cpu_map_entry { struct rcu_head rcu; struct work_struct kthread_stop_wq; + struct completion kthread_running; }; struct bpf_cpu_map { @@ -153,7 +155,6 @@ static void put_cpu_map_entry(struct bpf_cpu_map_entry *rcpu) static void cpu_map_kthread_stop(struct work_struct *work) { struct bpf_cpu_map_entry *rcpu; - int err; rcpu = container_of(work, struct bpf_cpu_map_entry, kthread_stop_wq); @@ -163,14 +164,7 @@ static void cpu_map_kthread_stop(struct work_struct *work) rcu_barrier(); /* kthread_stop will wake_up_process and wait for it to complete */ - err = kthread_stop(rcpu->kthread); - if (err) { - /* kthread_stop may be called before cpu_map_kthread_run - * is executed, so we need to release the memory related - * to rcpu. - */ - put_cpu_map_entry(rcpu); - } + kthread_stop(rcpu->kthread); } static void cpu_map_bpf_prog_run_skb(struct bpf_cpu_map_entry *rcpu, @@ -298,11 +292,11 @@ static int cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames, return nframes; } - static int cpu_map_kthread_run(void *data) { struct bpf_cpu_map_entry *rcpu = data; + complete(&rcpu->kthread_running); set_current_state(TASK_INTERRUPTIBLE); /* When kthread gives stop order, then rcpu have been disconnected @@ -467,6 +461,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value, goto free_ptr_ring; /* Setup kthread */ + init_completion(&rcpu->kthread_running); rcpu->kthread = kthread_create_on_node(cpu_map_kthread_run, rcpu, numa, "cpumap/%d/map:%d", cpu, map->id); @@ -480,6 +475,12 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value, kthread_bind(rcpu->kthread, cpu); wake_up_process(rcpu->kthread); + /* Make sure kthread has been running, so kthread_stop() will not + * stop the kthread prematurely and all pending frames or skbs + * will be handled by the kthread before kthread_stop() returns. + */ + wait_for_completion(&rcpu->kthread_running); + return rcpu; free_prog: -- cgit v1.2.3 From 7c62b75cd1a792e14b037fa4f61f9b18914e7de1 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Sat, 29 Jul 2023 17:51:07 +0800 Subject: bpf, cpumap: Handle skb as well when clean up ptr_ring The following warning was reported when running xdp_redirect_cpu with both skb-mode and stress-mode enabled: ------------[ cut here ]------------ Incorrect XDP memory type (-2128176192) usage WARNING: CPU: 7 PID: 1442 at net/core/xdp.c:405 Modules linked in: CPU: 7 PID: 1442 Comm: kworker/7:0 Tainted: G 6.5.0-rc2+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) Workqueue: events __cpu_map_entry_free RIP: 0010:__xdp_return+0x1e4/0x4a0 ...... Call Trace: ? show_regs+0x65/0x70 ? __warn+0xa5/0x240 ? __xdp_return+0x1e4/0x4a0 ...... xdp_return_frame+0x4d/0x150 __cpu_map_entry_free+0xf9/0x230 process_one_work+0x6b0/0xb80 worker_thread+0x96/0x720 kthread+0x1a5/0x1f0 ret_from_fork+0x3a/0x70 ret_from_fork_asm+0x1b/0x30 The reason for the warning is twofold. One is due to the kthread cpu_map_kthread_run() is stopped prematurely. Another one is __cpu_map_ring_cleanup() doesn't handle skb mode and treats skbs in ptr_ring as XDP frames. Prematurely-stopped kthread will be fixed by the preceding patch and ptr_ring will be empty when __cpu_map_ring_cleanup() is called. But as the comments in __cpu_map_ring_cleanup() said, handling and freeing skbs in ptr_ring as well to "catch any broken behaviour gracefully". Fixes: 11941f8a8536 ("bpf: cpumap: Implement generic cpumap") Signed-off-by: Hou Tao Acked-by: Jesper Dangaard Brouer Link: https://lore.kernel.org/r/20230729095107.1722450-3-houtao@huaweicloud.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/cpumap.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index 7eeb20025164..286ab3db0fde 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c @@ -131,11 +131,17 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring) * invoked cpu_map_kthread_stop(). Catch any broken behaviour * gracefully and warn once. */ - struct xdp_frame *xdpf; + void *ptr; - while ((xdpf = ptr_ring_consume(ring))) - if (WARN_ON_ONCE(xdpf)) - xdp_return_frame(xdpf); + while ((ptr = ptr_ring_consume(ring))) { + WARN_ON_ONCE(1); + if (unlikely(__ptr_test_bit(0, &ptr))) { + __ptr_clear_bit(0, &ptr); + kfree_skb(ptr); + continue; + } + xdp_return_frame(ptr); + } } static void put_cpu_map_entry(struct bpf_cpu_map_entry *rcpu) -- cgit v1.2.3 From 3044b16e7c6fe5d24b1cdbcf1bd0a9d92d1ebd81 Mon Sep 17 00:00:00 2001 From: valis Date: Sat, 29 Jul 2023 08:32:00 -0400 Subject: net/sched: cls_u32: No longer copy tcf_result on update to avoid use-after-free When u32_change() is called on an existing filter, the whole tcf_result struct is always copied into the new instance of the filter. This causes a problem when updating a filter bound to a class, as tcf_unbind_filter() is always called on the old instance in the success path, decreasing filter_cnt of the still referenced class and allowing it to be deleted, leading to a use-after-free. Fix this by no longer copying the tcf_result struct from the old filter. Fixes: de5df63228fc ("net: sched: cls_u32 changes to knode must appear atomic to readers") Reported-by: valis Reported-by: M A Ramdhan Signed-off-by: valis Signed-off-by: Jamal Hadi Salim Reviewed-by: Victor Nogueira Reviewed-by: Pedro Tammela Reviewed-by: M A Ramdhan Link: https://lore.kernel.org/r/20230729123202.72406-2-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/cls_u32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 907e58841fe8..da4c179a4d41 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -826,7 +826,6 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, new->ifindex = n->ifindex; new->fshift = n->fshift; - new->res = n->res; new->flags = n->flags; RCU_INIT_POINTER(new->ht_down, ht); -- cgit v1.2.3 From 76e42ae831991c828cffa8c37736ebfb831ad5ec Mon Sep 17 00:00:00 2001 From: valis Date: Sat, 29 Jul 2023 08:32:01 -0400 Subject: net/sched: cls_fw: No longer copy tcf_result on update to avoid use-after-free When fw_change() is called on an existing filter, the whole tcf_result struct is always copied into the new instance of the filter. This causes a problem when updating a filter bound to a class, as tcf_unbind_filter() is always called on the old instance in the success path, decreasing filter_cnt of the still referenced class and allowing it to be deleted, leading to a use-after-free. Fix this by no longer copying the tcf_result struct from the old filter. Fixes: e35a8ee5993b ("net: sched: fw use RCU") Reported-by: valis Reported-by: Bing-Jhong Billy Jheng Signed-off-by: valis Signed-off-by: Jamal Hadi Salim Reviewed-by: Victor Nogueira Reviewed-by: Pedro Tammela Reviewed-by: M A Ramdhan Link: https://lore.kernel.org/r/20230729123202.72406-3-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/cls_fw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 8641f8059317..c49d6af0e048 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -267,7 +267,6 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, return -ENOBUFS; fnew->id = f->id; - fnew->res = f->res; fnew->ifindex = f->ifindex; fnew->tp = f->tp; -- cgit v1.2.3 From b80b829e9e2c1b3f7aae34855e04d8f6ecaf13c8 Mon Sep 17 00:00:00 2001 From: valis Date: Sat, 29 Jul 2023 08:32:02 -0400 Subject: net/sched: cls_route: No longer copy tcf_result on update to avoid use-after-free When route4_change() is called on an existing filter, the whole tcf_result struct is always copied into the new instance of the filter. This causes a problem when updating a filter bound to a class, as tcf_unbind_filter() is always called on the old instance in the success path, decreasing filter_cnt of the still referenced class and allowing it to be deleted, leading to a use-after-free. Fix this by no longer copying the tcf_result struct from the old filter. Fixes: 1109c00547fc ("net: sched: RCU cls_route") Reported-by: valis Reported-by: Bing-Jhong Billy Jheng Signed-off-by: valis Signed-off-by: Jamal Hadi Salim Reviewed-by: Victor Nogueira Reviewed-by: Pedro Tammela Reviewed-by: M A Ramdhan Link: https://lore.kernel.org/r/20230729123202.72406-4-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/cls_route.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index d0c53724d3e8..1e20bbd687f1 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -513,7 +513,6 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, if (fold) { f->id = fold->id; f->iif = fold->iif; - f->res = fold->res; f->handle = fold->handle; f->tp = fold->tp; -- cgit v1.2.3 From 46d14e17095237007b59f56aae2d81ae2dcb0f93 Mon Sep 17 00:00:00 2001 From: Yan Zhao Date: Mon, 31 Jul 2023 19:20:33 +0800 Subject: drm/i915/gvt: Fix bug in getting msg length in AUX CH registers handler Msg length should be obtained from value written to AUX_CH_CTL register rather than from enum type of the register. Commit 0cad796a2269 ("drm/i915: Use REG_BIT() & co. for AUX CH registers") incorrectly calculates the msg_length from reg type and yields below warning in intel_gvt_i2c_handle_aux_ch_write(): "i915 0000:00:02.0: drm_WARN_ON(msg_length != 4)". Fixes: 0cad796a2269 ("drm/i915: Use REG_BIT() & co. for AUX CH registers") Signed-off-by: Yan Zhao Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20230731112033.7275-1-yan.y.zhao@intel.com Reviewed-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/edid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index 2a0438f12a14..af9afdb53c7f 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -491,7 +491,7 @@ void intel_gvt_i2c_handle_aux_ch_write(struct intel_vgpu *vgpu, return; } - msg_length = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, reg); + msg_length = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, value); // check the msg in DATA register. msg = vgpu_vreg(vgpu, offset + 4); -- cgit v1.2.3 From 34bc65d6d831200194c0b9a30fb8fe47faaf83d6 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 6 Jul 2023 11:37:04 -0700 Subject: perf pmus: Create placholder regardless of scanning core_only If scanning all PMUs the placeholder is still necessary if no core PMU is found. This situation occurs in perf test's parse-events test, when uncore events appear before core. Fixes: 628eaa4e877af823 ("perf pmus: Add placeholder core PMU") Signed-off-by: Ian Rogers Tested-by: Thomas Richter Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Link: https://lore.kernel.org/r/20230706183705.601412-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmus.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 3cd9de42139e..c58ba9fb6a36 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -152,16 +152,14 @@ static void pmu_read_sysfs(bool core_only) } closedir(dir); - if (core_only) { - if (!list_empty(&core_pmus)) - read_sysfs_core_pmus = true; - else { - if (perf_pmu__create_placeholder_core_pmu(&core_pmus)) - read_sysfs_core_pmus = true; - } - } else { + if (list_empty(&core_pmus)) { + if (!perf_pmu__create_placeholder_core_pmu(&core_pmus)) + pr_err("Failure to set up any core PMUs\n"); + } + if (!list_empty(&core_pmus)) { read_sysfs_core_pmus = true; - read_sysfs_all_pmus = true; + if (!core_only) + read_sysfs_all_pmus = true; } } -- cgit v1.2.3 From 07d2b820fd75b96f550c93503f19c8cfcbc577cf Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 6 Jul 2023 11:37:05 -0700 Subject: perf test parse-events: Test complex name has required event format test__checkevent_complex_name will use an "event" format which if not present, such as with a placeholder PMU, will cause test failures. Skip the test in this case to avoid failures in restricted environments. Add perf_pmu__has_format utility as a general PMU utility. Fixes: 628eaa4e877af823 ("perf pmus: Add placeholder core PMU") Signed-off-by: Ian Rogers Tested-by: Thomas Richter Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Link: https://lore.kernel.org/r/20230706183705.601412-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 12 +++++++++++- tools/perf/util/pmu.c | 11 +++++++++++ tools/perf/util/pmu.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b2f82847e4c3..658fb9599d95 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1631,6 +1631,16 @@ static bool test__pmu_cpu_valid(void) return !!perf_pmus__find("cpu"); } +static bool test__pmu_cpu_event_valid(void) +{ + struct perf_pmu *pmu = perf_pmus__find("cpu"); + + if (!pmu) + return false; + + return perf_pmu__has_format(pmu, "event"); +} + static bool test__intel_pt_valid(void) { return !!perf_pmus__find("intel_pt"); @@ -2179,7 +2189,7 @@ static const struct evlist_test test__events_pmu[] = { }, { .name = "cpu/name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks',period=0x1,event=0x2/ukp", - .valid = test__pmu_cpu_valid, + .valid = test__pmu_cpu_event_valid, .check = test__checkevent_complex_name, /* 3 */ }, diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 7f984a7f16ca..28380e7aa8d0 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1440,6 +1440,17 @@ void perf_pmu__del_formats(struct list_head *formats) } } +bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name) +{ + struct perf_pmu_format *format; + + list_for_each_entry(format, &pmu->format, list) { + if (!strcmp(format->name, name)) + return true; + } + return false; +} + bool is_pmu_core(const char *name) { return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 203b92860e3c..6b414cecbad2 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -234,6 +234,7 @@ int perf_pmu__new_format(struct list_head *list, char *name, void perf_pmu__set_format(unsigned long *bits, long from, long to); int perf_pmu__format_parse(int dirfd, struct list_head *head); void perf_pmu__del_formats(struct list_head *formats); +bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); bool is_pmu_core(const char *name); bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); -- cgit v1.2.3 From 13d2618b48f15966d1adfe1ff6a1985f5eef40ba Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Fri, 28 Jul 2023 08:44:11 +0200 Subject: bpf: sockmap: Remove preempt_disable in sock_map_sk_acquire Disabling preemption in sock_map_sk_acquire conflicts with GFP_ATOMIC allocation later in sk_psock_init_link on PREEMPT_RT kernels, since GFP_ATOMIC might sleep on RT (see bpf: Make BPF and PREEMPT_RT co-exist patchset notes for details). This causes calling bpf_map_update_elem on BPF_MAP_TYPE_SOCKMAP maps to BUG (sleeping function called from invalid context) on RT kernels. preempt_disable was introduced together with lock_sk and rcu_read_lock in commit 99ba2b5aba24e ("bpf: sockhash, disallow bpf_tcp_close and update in parallel"), probably to match disabled migration of BPF programs, and is no longer necessary. Remove preempt_disable to fix BUG in sock_map_update_common on RT. Signed-off-by: Tomas Glozar Reviewed-by: Jakub Sitnicki Link: https://lore.kernel.org/all/20200224140131.461979697@linutronix.de/ Fixes: 99ba2b5aba24 ("bpf: sockhash, disallow bpf_tcp_close and update in parallel") Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20230728064411.305576-1-tglozar@redhat.com Signed-off-by: Paolo Abeni --- net/core/sock_map.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 19538d628714..08ab108206bf 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -115,7 +115,6 @@ static void sock_map_sk_acquire(struct sock *sk) __acquires(&sk->sk_lock.slock) { lock_sock(sk); - preempt_disable(); rcu_read_lock(); } @@ -123,7 +122,6 @@ static void sock_map_sk_release(struct sock *sk) __releases(&sk->sk_lock.slock) { rcu_read_unlock(); - preempt_enable(); release_sock(sk); } -- cgit v1.2.3 From 94c43de73521d8ed7ebcfc6191d9dace1cbf7caa Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 19 Jul 2023 14:54:59 +0800 Subject: erofs: fix wrong primary bvec selection on deduplicated extents When handling deduplicated compressed data, there can be multiple decompressed extents pointing to the same compressed data in one shot. In such cases, the bvecs which belong to the longest extent will be selected as the primary bvecs for real decompressors to decode and the other duplicated bvecs will be directly copied from the primary bvecs. Previously, only relative offsets of the longest extent were checked to decompress the primary bvecs. On rare occasions, it can be incorrect if there are several extents with the same start relative offset. As a result, some short bvecs could be selected for decompression and then cause data corruption. For example, as Shijie Sun reported off-list, considering the following extents of a file: 117: 903345.. 915250 | 11905 : 385024.. 389120 | 4096 ... 119: 919729.. 930323 | 10594 : 385024.. 389120 | 4096 ... 124: 968881.. 980786 | 11905 : 385024.. 389120 | 4096 The start relative offset is the same: 2225, but extent 119 (919729.. 930323) is shorter than the others. Let's restrict the bvec length in addition to the start offset if bvecs are not full. Reported-by: Shijie Sun Fixes: 5c2a64252c5d ("erofs: introduce partial-referenced pclusters") Tested-by Shijie Sun Reviewed-by: Yue Hu Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20230719065459.60083-1-hsiangkao@linux.alibaba.com --- fs/erofs/zdata.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index b69d89a11dd0..de4f12152b62 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -1144,10 +1144,11 @@ static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be, struct z_erofs_bvec *bvec) { struct z_erofs_bvec_item *item; + unsigned int pgnr; - if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK)) { - unsigned int pgnr; - + if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) && + (bvec->end == PAGE_SIZE || + bvec->offset + bvec->end == be->pcl->length)) { pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT; DBG_BUGON(pgnr >= be->nr_pages); if (!be->decompressed_pages[pgnr]) { -- cgit v1.2.3 From 4da3c7183e186afe8196160f16d5a0248a24e45d Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 1 Aug 2023 09:47:37 +0800 Subject: erofs: drop unnecessary WARN_ON() in erofs_kill_sb() Previously, .kill_sb() will be called only after fill_super fails. It will be changed [1]. Besides, checking for s_magic in erofs_kill_sb() is unnecessary from any point of view. Let's get rid of it now. [1] https://lore.kernel.org/r/20230731-flugbereit-wohnlage-78acdf95ab7e@brauner Signed-off-by: Gao Xiang Reviewed-by: Christoph Hellwig Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20230801014737.28614-1-hsiangkao@linux.alibaba.com --- fs/erofs/super.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 9d6a3c6158bd..566f68ddfa36 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -889,8 +889,6 @@ static void erofs_kill_sb(struct super_block *sb) { struct erofs_sb_info *sbi; - WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC); - /* pseudo mount for anon inodes */ if (sb->s_flags & SB_KERNMOUNT) { kill_anon_super(sb); -- cgit v1.2.3 From d14560ac1b595aa2e792365e91fea6aeaee66c2b Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 25 Jul 2023 02:19:44 +0200 Subject: drm/i915/gt: Cleanup aux invalidation registers Fix the 'NV' definition postfix that is supposed to be INV. Take the chance to also order properly the registers based on their address and call the GEN12_GFX_CCS_AUX_INV address as GEN12_CCS_AUX_INV like all the other similar registers. Remove also VD1, VD3 and VE1 registers that don't exist and add BCS0 and CCS0. Signed-off-by: Andi Shyti Cc: # v5.8+ Reviewed-by: Nirmoy Das Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-2-andi.shyti@linux.intel.com (cherry picked from commit 2f0b927d3ca3440445975ebde27f3df1c3ed6f76) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 8 ++++---- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 16 ++++++++-------- drivers/gpu/drm/i915/gt/intel_lrc.c | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 23857cc08eca..563efee05560 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -287,8 +287,8 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) if (!HAS_FLAT_CCS(rq->engine->i915)) { /* hsdes: 1809175790 */ - cs = gen12_emit_aux_table_inv(rq->engine->gt, - cs, GEN12_GFX_CCS_AUX_NV); + cs = gen12_emit_aux_table_inv(rq->engine->gt, cs, + GEN12_CCS_AUX_INV); } *cs++ = preparser_disable(false); @@ -348,10 +348,10 @@ int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) if (aux_inv) { /* hsdes: 1809175790 */ if (rq->engine->class == VIDEO_DECODE_CLASS) cs = gen12_emit_aux_table_inv(rq->engine->gt, - cs, GEN12_VD0_AUX_NV); + cs, GEN12_VD0_AUX_INV); else cs = gen12_emit_aux_table_inv(rq->engine->gt, - cs, GEN12_VE0_AUX_NV); + cs, GEN12_VE0_AUX_INV); } if (mode & EMIT_INVALIDATE) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 718cb2c80f79..2cdfb2f713d0 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -332,9 +332,11 @@ #define GEN8_PRIVATE_PAT_HI _MMIO(0x40e0 + 4) #define GEN10_PAT_INDEX(index) _MMIO(0x40e0 + (index) * 4) #define BSD_HWS_PGA_GEN7 _MMIO(0x4180) -#define GEN12_GFX_CCS_AUX_NV _MMIO(0x4208) -#define GEN12_VD0_AUX_NV _MMIO(0x4218) -#define GEN12_VD1_AUX_NV _MMIO(0x4228) + +#define GEN12_CCS_AUX_INV _MMIO(0x4208) +#define GEN12_VD0_AUX_INV _MMIO(0x4218) +#define GEN12_VE0_AUX_INV _MMIO(0x4238) +#define GEN12_BCS0_AUX_INV _MMIO(0x4248) #define GEN8_RTCR _MMIO(0x4260) #define GEN8_M1TCR _MMIO(0x4264) @@ -342,14 +344,12 @@ #define GEN8_BTCR _MMIO(0x426c) #define GEN8_VTCR _MMIO(0x4270) -#define GEN12_VD2_AUX_NV _MMIO(0x4298) -#define GEN12_VD3_AUX_NV _MMIO(0x42a8) -#define GEN12_VE0_AUX_NV _MMIO(0x4238) - #define BLT_HWS_PGA_GEN7 _MMIO(0x4280) -#define GEN12_VE1_AUX_NV _MMIO(0x42b8) +#define GEN12_VD2_AUX_INV _MMIO(0x4298) +#define GEN12_CCS0_AUX_INV _MMIO(0x42c8) #define AUX_INV REG_BIT(0) + #define VEBOX_HWS_PGA_GEN7 _MMIO(0x4380) #define GEN12_AUX_ERR_DBG _MMIO(0x43f4) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index a4ec20aaafe2..325f3dbfb90e 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -1367,7 +1367,7 @@ gen12_emit_indirect_ctx_rcs(const struct intel_context *ce, u32 *cs) /* hsdes: 1809175790 */ if (!HAS_FLAT_CCS(ce->engine->i915)) cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_GFX_CCS_AUX_NV); + cs, GEN12_CCS_AUX_INV); /* Wa_16014892111 */ if (IS_MTL_GRAPHICS_STEP(ce->engine->i915, M, STEP_A0, STEP_B0) || @@ -1396,10 +1396,10 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) if (!HAS_FLAT_CCS(ce->engine->i915)) { if (ce->engine->class == VIDEO_DECODE_CLASS) cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_VD0_AUX_NV); + cs, GEN12_VD0_AUX_INV); else if (ce->engine->class == VIDEO_ENHANCEMENT_CLASS) cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_VE0_AUX_NV); + cs, GEN12_VE0_AUX_INV); } return cs; -- cgit v1.2.3 From b2f59e9026038a5bbcbc0019fa58f963138211ee Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 25 Jul 2023 02:19:45 +0200 Subject: drm/i915: Add the gen12_needs_ccs_aux_inv helper We always assumed that a device might either have AUX or FLAT CCS, but this is an approximation that is not always true, e.g. PVC represents an exception. Set the basis for future finer selection by implementing a boolean gen12_needs_ccs_aux_inv() function that tells whether aux invalidation is needed or not. Currently PVC is the only exception to the above mentioned rule. Requires: 059ae7ae2a1c ("drm/i915/gt: Cleanup aux invalidation registers") Signed-off-by: Andi Shyti Cc: Matt Roper Cc: Jonathan Cavitt Cc: # v5.8+ Reviewed-by: Matt Roper Reviewed-by: Andrzej Hajda Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-3-andi.shyti@linux.intel.com (cherry picked from commit c827655b87ad201ebe36f2e28d16b5491c8f7801) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 563efee05560..460c9225a50f 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -165,6 +165,18 @@ static u32 preparser_disable(bool state) return MI_ARB_CHECK | 1 << 8 | state; } +static bool gen12_needs_ccs_aux_inv(struct intel_engine_cs *engine) +{ + if (IS_PONTEVECCHIO(engine->i915)) + return false; + + /* + * so far platforms supported by i915 having + * flat ccs do not require AUX invalidation + */ + return !HAS_FLAT_CCS(engine->i915); +} + u32 *gen12_emit_aux_table_inv(struct intel_gt *gt, u32 *cs, const i915_reg_t inv_reg) { u32 gsi_offset = gt->uncore->gsi_offset; @@ -267,7 +279,7 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) else if (engine->class == COMPUTE_CLASS) flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; - if (!HAS_FLAT_CCS(rq->engine->i915)) + if (gen12_needs_ccs_aux_inv(rq->engine)) count = 8 + 4; else count = 8; @@ -285,7 +297,7 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) cs = gen8_emit_pipe_control(cs, flags, LRC_PPHWSP_SCRATCH_ADDR); - if (!HAS_FLAT_CCS(rq->engine->i915)) { + if (gen12_needs_ccs_aux_inv(rq->engine)) { /* hsdes: 1809175790 */ cs = gen12_emit_aux_table_inv(rq->engine->gt, cs, GEN12_CCS_AUX_INV); @@ -307,7 +319,7 @@ int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) if (mode & EMIT_INVALIDATE) { cmd += 2; - if (!HAS_FLAT_CCS(rq->engine->i915) && + if (gen12_needs_ccs_aux_inv(rq->engine) && (rq->engine->class == VIDEO_DECODE_CLASS || rq->engine->class == VIDEO_ENHANCEMENT_CLASS)) { aux_inv = rq->engine->mask & -- cgit v1.2.3 From 78a6ccd65fa3a7cc697810db079cc4b84dff03d5 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 25 Jul 2023 02:19:46 +0200 Subject: drm/i915/gt: Ensure memory quiesced before invalidation All memory traffic must be quiesced before requesting an aux invalidation on platforms that use Aux CCS. Fixes: 972282c4cf24 ("drm/i915/gen12: Add aux table invalidate for all engines") Requires: a2a4aa0eef3b ("drm/i915: Add the gen12_needs_ccs_aux_inv helper") Signed-off-by: Jonathan Cavitt Signed-off-by: Andi Shyti Cc: # v5.8+ Reviewed-by: Nirmoy Das Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-4-andi.shyti@linux.intel.com (cherry picked from commit ad8ebf12217e451cd19804b1c3e97ad56491c74a) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 460c9225a50f..6210b38a2d38 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -214,7 +214,11 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) { struct intel_engine_cs *engine = rq->engine; - if (mode & EMIT_FLUSH) { + /* + * On Aux CCS platforms the invalidation of the Aux + * table requires quiescing memory traffic beforehand + */ + if (mode & EMIT_FLUSH || gen12_needs_ccs_aux_inv(engine)) { u32 flags = 0; int err; u32 *cs; -- cgit v1.2.3 From 592b228f12e15867a63e3a6eeeb54c5c12662a62 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 25 Jul 2023 02:19:47 +0200 Subject: drm/i915/gt: Rename flags with bit_group_X according to the datasheet In preparation of the next patch align with the datasheet (BSPEC 47112) with the naming of the pipe control set of flag values. The variable "flags" in gen12_emit_flush_rcs() is applied as a set of flags called Bit Group 1. Define also the Bit Group 0 as bit_group_0 where currently only PIPE_CONTROL0_HDC_PIPELINE_FLUSH bit is set. Signed-off-by: Andi Shyti Cc: # v5.8+ Reviewed-by: Matt Roper Reviewed-by: Andrzej Hajda Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-5-andi.shyti@linux.intel.com (cherry picked from commit f2dcd21d5a22e13f2fbfe7ab65149038b93cf2ff) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 34 +++++++++++++++++--------------- drivers/gpu/drm/i915/gt/gen8_engine_cs.h | 18 ++++++++++------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 6210b38a2d38..5d2175e918dd 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -219,7 +219,8 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) * table requires quiescing memory traffic beforehand */ if (mode & EMIT_FLUSH || gen12_needs_ccs_aux_inv(engine)) { - u32 flags = 0; + u32 bit_group_0 = 0; + u32 bit_group_1 = 0; int err; u32 *cs; @@ -227,32 +228,33 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) if (err) return err; - flags |= PIPE_CONTROL_TILE_CACHE_FLUSH; - flags |= PIPE_CONTROL_FLUSH_L3; - flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; - flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; + bit_group_0 |= PIPE_CONTROL0_HDC_PIPELINE_FLUSH; + + bit_group_1 |= PIPE_CONTROL_TILE_CACHE_FLUSH; + bit_group_1 |= PIPE_CONTROL_FLUSH_L3; + bit_group_1 |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; + bit_group_1 |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; /* Wa_1409600907:tgl,adl-p */ - flags |= PIPE_CONTROL_DEPTH_STALL; - flags |= PIPE_CONTROL_DC_FLUSH_ENABLE; - flags |= PIPE_CONTROL_FLUSH_ENABLE; + bit_group_1 |= PIPE_CONTROL_DEPTH_STALL; + bit_group_1 |= PIPE_CONTROL_DC_FLUSH_ENABLE; + bit_group_1 |= PIPE_CONTROL_FLUSH_ENABLE; - flags |= PIPE_CONTROL_STORE_DATA_INDEX; - flags |= PIPE_CONTROL_QW_WRITE; + bit_group_1 |= PIPE_CONTROL_STORE_DATA_INDEX; + bit_group_1 |= PIPE_CONTROL_QW_WRITE; - flags |= PIPE_CONTROL_CS_STALL; + bit_group_1 |= PIPE_CONTROL_CS_STALL; if (!HAS_3D_PIPELINE(engine->i915)) - flags &= ~PIPE_CONTROL_3D_ARCH_FLAGS; + bit_group_1 &= ~PIPE_CONTROL_3D_ARCH_FLAGS; else if (engine->class == COMPUTE_CLASS) - flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; + bit_group_1 &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; cs = intel_ring_begin(rq, 6); if (IS_ERR(cs)) return PTR_ERR(cs); - cs = gen12_emit_pipe_control(cs, - PIPE_CONTROL0_HDC_PIPELINE_FLUSH, - flags, LRC_PPHWSP_SCRATCH_ADDR); + cs = gen12_emit_pipe_control(cs, bit_group_0, bit_group_1, + LRC_PPHWSP_SCRATCH_ADDR); intel_ring_advance(rq, cs); } diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h index 655e5c00ddc2..a44eda096557 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h @@ -49,25 +49,29 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs); u32 *gen12_emit_aux_table_inv(struct intel_gt *gt, u32 *cs, const i915_reg_t inv_reg); static inline u32 * -__gen8_emit_pipe_control(u32 *batch, u32 flags0, u32 flags1, u32 offset) +__gen8_emit_pipe_control(u32 *batch, u32 bit_group_0, + u32 bit_group_1, u32 offset) { memset(batch, 0, 6 * sizeof(u32)); - batch[0] = GFX_OP_PIPE_CONTROL(6) | flags0; - batch[1] = flags1; + batch[0] = GFX_OP_PIPE_CONTROL(6) | bit_group_0; + batch[1] = bit_group_1; batch[2] = offset; return batch + 6; } -static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset) +static inline u32 *gen8_emit_pipe_control(u32 *batch, + u32 bit_group_1, u32 offset) { - return __gen8_emit_pipe_control(batch, 0, flags, offset); + return __gen8_emit_pipe_control(batch, 0, bit_group_1, offset); } -static inline u32 *gen12_emit_pipe_control(u32 *batch, u32 flags0, u32 flags1, u32 offset) +static inline u32 *gen12_emit_pipe_control(u32 *batch, u32 bit_group_0, + u32 bit_group_1, u32 offset) { - return __gen8_emit_pipe_control(batch, flags0, flags1, offset); + return __gen8_emit_pipe_control(batch, bit_group_0, + bit_group_1, offset); } static inline u32 * -- cgit v1.2.3 From 824df77ab2107d8d4740b834b276681a41ae1ac8 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 25 Jul 2023 02:19:48 +0200 Subject: drm/i915/gt: Enable the CCS_FLUSH bit in the pipe control and in the CS Enable the CCS_FLUSH bit 13 in the control pipe for render and compute engines in platforms starting from Meteor Lake (BSPEC 43904 and 47112). For the copy engine add MI_FLUSH_DW_CCS (bit 16) in the command streamer. Fixes: 972282c4cf24 ("drm/i915/gen12: Add aux table invalidate for all engines") Requires: 8da173db894a ("drm/i915/gt: Rename flags with bit_group_X according to the datasheet") Signed-off-by: Andi Shyti Cc: Jonathan Cavitt Cc: Nirmoy Das Cc: # v5.8+ Reviewed-by: Matt Roper Reviewed-by: Andrzej Hajda Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-6-andi.shyti@linux.intel.com (cherry picked from commit b70df82b428774875c7c56d3808102165891547c) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 11 +++++++++++ drivers/gpu/drm/i915/gt/intel_gpu_commands.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 5d2175e918dd..ec54d36eaef7 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -230,6 +230,13 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) bit_group_0 |= PIPE_CONTROL0_HDC_PIPELINE_FLUSH; + /* + * When required, in MTL and beyond platforms we + * need to set the CCS_FLUSH bit in the pipe control + */ + if (GRAPHICS_VER_FULL(rq->i915) >= IP_VER(12, 70)) + bit_group_0 |= PIPE_CONTROL_CCS_FLUSH; + bit_group_1 |= PIPE_CONTROL_TILE_CACHE_FLUSH; bit_group_1 |= PIPE_CONTROL_FLUSH_L3; bit_group_1 |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; @@ -356,6 +363,10 @@ int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) cmd |= MI_INVALIDATE_TLB; if (rq->engine->class == VIDEO_DECODE_CLASS) cmd |= MI_INVALIDATE_BSD; + + if (gen12_needs_ccs_aux_inv(rq->engine) && + rq->engine->class == COPY_ENGINE_CLASS) + cmd |= MI_FLUSH_DW_CCS; } *cs++ = cmd; diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h index 5d143e2a8db0..5df7cce23197 100644 --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h @@ -299,6 +299,7 @@ #define PIPE_CONTROL_QW_WRITE (1<<14) #define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) #define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_CCS_FLUSH (1<<13) /* MTL+ */ #define PIPE_CONTROL_WRITE_FLUSH (1<<12) #define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12) /* gen6+ */ #define PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE (1<<11) /* MBZ on ILK */ -- cgit v1.2.3 From 0fde2f23516a00fd90dfb980b66b4665fcbfa659 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 25 Jul 2023 02:19:49 +0200 Subject: drm/i915/gt: Poll aux invalidation register bit on invalidation For platforms that use Aux CCS, wait for aux invalidation to complete by checking the aux invalidation register bit is cleared. Fixes: 972282c4cf24 ("drm/i915/gen12: Add aux table invalidate for all engines") Signed-off-by: Jonathan Cavitt Signed-off-by: Andi Shyti Cc: # v5.8+ Reviewed-by: Nirmoy Das Reviewed-by: Andrzej Hajda Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-7-andi.shyti@linux.intel.com (cherry picked from commit d459c86f00aa98028d155a012c65dc42f7c37e76) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 17 ++++++++++++----- drivers/gpu/drm/i915/gt/intel_gpu_commands.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index ec54d36eaef7..ec7a0ddf9e12 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -184,7 +184,15 @@ u32 *gen12_emit_aux_table_inv(struct intel_gt *gt, u32 *cs, const i915_reg_t inv *cs++ = MI_LOAD_REGISTER_IMM(1) | MI_LRI_MMIO_REMAP_EN; *cs++ = i915_mmio_reg_offset(inv_reg) + gsi_offset; *cs++ = AUX_INV; - *cs++ = MI_NOOP; + + *cs++ = MI_SEMAPHORE_WAIT_TOKEN | + MI_SEMAPHORE_REGISTER_POLL | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD; + *cs++ = 0; + *cs++ = i915_mmio_reg_offset(inv_reg) + gsi_offset; + *cs++ = 0; + *cs++ = 0; return cs; } @@ -292,10 +300,9 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) else if (engine->class == COMPUTE_CLASS) flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; + count = 8; if (gen12_needs_ccs_aux_inv(rq->engine)) - count = 8 + 4; - else - count = 8; + count += 8; cs = intel_ring_begin(rq, count); if (IS_ERR(cs)) @@ -338,7 +345,7 @@ int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) aux_inv = rq->engine->mask & ~GENMASK(_BCS(I915_MAX_BCS - 1), BCS0); if (aux_inv) - cmd += 4; + cmd += 8; } } diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h index 5df7cce23197..2bd8d98d2110 100644 --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h @@ -121,6 +121,7 @@ #define MI_SEMAPHORE_TARGET(engine) ((engine)<<15) #define MI_SEMAPHORE_WAIT MI_INSTR(0x1c, 2) /* GEN8+ */ #define MI_SEMAPHORE_WAIT_TOKEN MI_INSTR(0x1c, 3) /* GEN12+ */ +#define MI_SEMAPHORE_REGISTER_POLL (1 << 16) #define MI_SEMAPHORE_POLL (1 << 15) #define MI_SEMAPHORE_SAD_GT_SDD (0 << 12) #define MI_SEMAPHORE_SAD_GTE_SDD (1 << 12) -- cgit v1.2.3 From 6a35f22d222528e1b157c6978c9424d2f8cbe0a1 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 25 Jul 2023 02:19:50 +0200 Subject: drm/i915/gt: Support aux invalidation on all engines Perform some refactoring with the purpose of keeping in one single place all the operations around the aux table invalidation. With this refactoring add more engines where the invalidation should be performed. Fixes: 972282c4cf24 ("drm/i915/gen12: Add aux table invalidate for all engines") Signed-off-by: Andi Shyti Cc: Jonathan Cavitt Cc: Matt Roper Cc: # v5.8+ Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20230725001950.1014671-8-andi.shyti@linux.intel.com (cherry picked from commit 76ff7789d6e63d1a10b3b58f5c70b2e640c7a880) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 66 ++++++++++++++++++-------------- drivers/gpu/drm/i915/gt/gen8_engine_cs.h | 3 +- drivers/gpu/drm/i915/gt/intel_lrc.c | 17 +------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index ec7a0ddf9e12..2702ad4c26c8 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -165,21 +165,47 @@ static u32 preparser_disable(bool state) return MI_ARB_CHECK | 1 << 8 | state; } +static i915_reg_t gen12_get_aux_inv_reg(struct intel_engine_cs *engine) +{ + switch (engine->id) { + case RCS0: + return GEN12_CCS_AUX_INV; + case BCS0: + return GEN12_BCS0_AUX_INV; + case VCS0: + return GEN12_VD0_AUX_INV; + case VCS2: + return GEN12_VD2_AUX_INV; + case VECS0: + return GEN12_VE0_AUX_INV; + case CCS0: + return GEN12_CCS0_AUX_INV; + default: + return INVALID_MMIO_REG; + } +} + static bool gen12_needs_ccs_aux_inv(struct intel_engine_cs *engine) { + i915_reg_t reg = gen12_get_aux_inv_reg(engine); + if (IS_PONTEVECCHIO(engine->i915)) return false; /* - * so far platforms supported by i915 having - * flat ccs do not require AUX invalidation + * So far platforms supported by i915 having flat ccs do not require + * AUX invalidation. Check also whether the engine requires it. */ - return !HAS_FLAT_CCS(engine->i915); + return i915_mmio_reg_valid(reg) && !HAS_FLAT_CCS(engine->i915); } -u32 *gen12_emit_aux_table_inv(struct intel_gt *gt, u32 *cs, const i915_reg_t inv_reg) +u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs) { - u32 gsi_offset = gt->uncore->gsi_offset; + i915_reg_t inv_reg = gen12_get_aux_inv_reg(engine); + u32 gsi_offset = engine->gt->uncore->gsi_offset; + + if (!gen12_needs_ccs_aux_inv(engine)) + return cs; *cs++ = MI_LOAD_REGISTER_IMM(1) | MI_LRI_MMIO_REMAP_EN; *cs++ = i915_mmio_reg_offset(inv_reg) + gsi_offset; @@ -317,11 +343,7 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) cs = gen8_emit_pipe_control(cs, flags, LRC_PPHWSP_SCRATCH_ADDR); - if (gen12_needs_ccs_aux_inv(rq->engine)) { - /* hsdes: 1809175790 */ - cs = gen12_emit_aux_table_inv(rq->engine->gt, cs, - GEN12_CCS_AUX_INV); - } + cs = gen12_emit_aux_table_inv(engine, cs); *cs++ = preparser_disable(false); intel_ring_advance(rq, cs); @@ -332,21 +354,14 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) { - intel_engine_mask_t aux_inv = 0; - u32 cmd, *cs; + u32 cmd = 4; + u32 *cs; - cmd = 4; if (mode & EMIT_INVALIDATE) { cmd += 2; - if (gen12_needs_ccs_aux_inv(rq->engine) && - (rq->engine->class == VIDEO_DECODE_CLASS || - rq->engine->class == VIDEO_ENHANCEMENT_CLASS)) { - aux_inv = rq->engine->mask & - ~GENMASK(_BCS(I915_MAX_BCS - 1), BCS0); - if (aux_inv) - cmd += 8; - } + if (gen12_needs_ccs_aux_inv(rq->engine)) + cmd += 8; } cs = intel_ring_begin(rq, cmd); @@ -381,14 +396,7 @@ int gen12_emit_flush_xcs(struct i915_request *rq, u32 mode) *cs++ = 0; /* upper addr */ *cs++ = 0; /* value */ - if (aux_inv) { /* hsdes: 1809175790 */ - if (rq->engine->class == VIDEO_DECODE_CLASS) - cs = gen12_emit_aux_table_inv(rq->engine->gt, - cs, GEN12_VD0_AUX_INV); - else - cs = gen12_emit_aux_table_inv(rq->engine->gt, - cs, GEN12_VE0_AUX_INV); - } + cs = gen12_emit_aux_table_inv(rq->engine, cs); if (mode & EMIT_INVALIDATE) *cs++ = preparser_disable(false); diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h index a44eda096557..867ba697aceb 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h @@ -13,6 +13,7 @@ #include "intel_gt_regs.h" #include "intel_gpu_commands.h" +struct intel_engine_cs; struct intel_gt; struct i915_request; @@ -46,7 +47,7 @@ u32 *gen8_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs); u32 *gen11_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs); u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs); -u32 *gen12_emit_aux_table_inv(struct intel_gt *gt, u32 *cs, const i915_reg_t inv_reg); +u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs); static inline u32 * __gen8_emit_pipe_control(u32 *batch, u32 bit_group_0, diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 325f3dbfb90e..9477c2422321 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -1364,10 +1364,7 @@ gen12_emit_indirect_ctx_rcs(const struct intel_context *ce, u32 *cs) IS_DG2_G11(ce->engine->i915)) cs = gen8_emit_pipe_control(cs, PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, 0); - /* hsdes: 1809175790 */ - if (!HAS_FLAT_CCS(ce->engine->i915)) - cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_CCS_AUX_INV); + cs = gen12_emit_aux_table_inv(ce->engine, cs); /* Wa_16014892111 */ if (IS_MTL_GRAPHICS_STEP(ce->engine->i915, M, STEP_A0, STEP_B0) || @@ -1392,17 +1389,7 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, 0); - /* hsdes: 1809175790 */ - if (!HAS_FLAT_CCS(ce->engine->i915)) { - if (ce->engine->class == VIDEO_DECODE_CLASS) - cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_VD0_AUX_INV); - else if (ce->engine->class == VIDEO_ENHANCEMENT_CLASS) - cs = gen12_emit_aux_table_inv(ce->engine->gt, - cs, GEN12_VE0_AUX_INV); - } - - return cs; + return gen12_emit_aux_table_inv(ce->engine, cs); } static void -- cgit v1.2.3 From a337b64f0d5717248a0c894e2618e658e6a9de9f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 20 Jul 2023 11:35:44 +0200 Subject: drm/i915: Fix premature release of request's reusable memory Infinite waits for completion of GPU activity have been observed in CI, mostly inside __i915_active_wait(), triggered by igt@gem_barrier_race or igt@perf@stress-open-close. Root cause analysis, based of ftrace dumps generated with a lot of extra trace_printk() calls added to the code, revealed loops of request dependencies being accidentally built, preventing the requests from being processed, each waiting for completion of another one's activity. After we substitute a new request for a last active one tracked on a timeline, we set up a dependency of our new request to wait on completion of current activity of that previous one. While doing that, we must take care of keeping the old request still in memory until we use its attributes for setting up that await dependency, or we can happen to set up the await dependency on an unrelated request that already reuses the memory previously allocated to the old one, already released. Combined with perf adding consecutive kernel context remote requests to different user context timelines, unresolvable loops of await dependencies can be built, leading do infinite waits. We obtain a pointer to the previous request to wait upon when we substitute it with a pointer to our new request in an active tracker, e.g. in intel_timeline.last_request. In some processing paths we protect that old request from being freed before we use it by getting a reference to it under RCU protection, but in others, e.g. __i915_request_commit() -> __i915_request_add_to_timeline() -> __i915_request_ensure_ordering(), we don't. But anyway, since the requests' memory is SLAB_FAILSAFE_BY_RCU, that RCU protection is not sufficient against reuse of memory. We could protect i915_request's memory from being prematurely reused by calling its release function via call_rcu() and using rcu_read_lock() consequently, as proposed in v1. However, that approach leads to significant (up to 10 times) increase of SLAB utilization by i915_request SLAB cache. Another potential approach is to take a reference to the previous active fence. When updating an active fence tracker, we first lock the new fence, substitute a pointer of the current active fence with the new one, then we lock the substituted fence. With this approach, there is a time window after the substitution and before the lock when the request can be concurrently released by an interrupt handler and its memory reused, then we may happen to lock and return a new, unrelated request. Always get a reference to the current active fence first, before replacing it with a new one. Having it protected from premature release and reuse, lock it and then replace with the new one but only if not yet signalled via a potential concurrent interrupt nor replaced with another one by a potential concurrent thread, otherwise retry, starting from getting a reference to the new current one. Adjust users to not get a reference to the previous active fence themselves and always put the reference got by __i915_active_fence_set() when no longer needed. v3: Fix lockdep splat reports and other issues caused by incorrect use of try_cmpxchg() (use (cmpxchg() != prev) instead) v2: Protect request's memory by getting a reference to it in favor of delegating its release to call_rcu() (Chris) Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/8211 Fixes: df9f85d8582e ("drm/i915: Serialise i915_active_fence_set() with itself") Suggested-by: Chris Wilson Signed-off-by: Janusz Krzysztofik Cc: # v5.6+ Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20230720093543.832147-2-janusz.krzysztofik@linux.intel.com (cherry picked from commit 946e047a3d88d46d15b5c5af0414098e12b243f7) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_active.c | 99 ++++++++++++++++++++++++++----------- drivers/gpu/drm/i915/i915_request.c | 11 +++++ 2 files changed, 81 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index 8ef93889061a..5ec293011d99 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -449,8 +449,11 @@ int i915_active_add_request(struct i915_active *ref, struct i915_request *rq) } } while (unlikely(is_barrier(active))); - if (!__i915_active_fence_set(active, fence)) + fence = __i915_active_fence_set(active, fence); + if (!fence) __i915_active_acquire(ref); + else + dma_fence_put(fence); out: i915_active_release(ref); @@ -469,13 +472,9 @@ __i915_active_set_fence(struct i915_active *ref, return NULL; } - rcu_read_lock(); prev = __i915_active_fence_set(active, fence); - if (prev) - prev = dma_fence_get_rcu(prev); - else + if (!prev) __i915_active_acquire(ref); - rcu_read_unlock(); return prev; } @@ -1019,10 +1018,11 @@ void i915_request_add_active_barriers(struct i915_request *rq) * * Records the new @fence as the last active fence along its timeline in * this active tracker, moving the tracking callbacks from the previous - * fence onto this one. Returns the previous fence (if not already completed), - * which the caller must ensure is executed before the new fence. To ensure - * that the order of fences within the timeline of the i915_active_fence is - * understood, it should be locked by the caller. + * fence onto this one. Gets and returns a reference to the previous fence + * (if not already completed), which the caller must put after making sure + * that it is executed before the new fence. To ensure that the order of + * fences within the timeline of the i915_active_fence is understood, it + * should be locked by the caller. */ struct dma_fence * __i915_active_fence_set(struct i915_active_fence *active, @@ -1031,7 +1031,23 @@ __i915_active_fence_set(struct i915_active_fence *active, struct dma_fence *prev; unsigned long flags; - if (fence == rcu_access_pointer(active->fence)) + /* + * In case of fences embedded in i915_requests, their memory is + * SLAB_FAILSAFE_BY_RCU, then it can be reused right after release + * by new requests. Then, there is a risk of passing back a pointer + * to a new, completely unrelated fence that reuses the same memory + * while tracked under a different active tracker. Combined with i915 + * perf open/close operations that build await dependencies between + * engine kernel context requests and user requests from different + * timelines, this can lead to dependency loops and infinite waits. + * + * As a countermeasure, we try to get a reference to the active->fence + * first, so if we succeed and pass it back to our user then it is not + * released and potentially reused by an unrelated request before the + * user has a chance to set up an await dependency on it. + */ + prev = i915_active_fence_get(active); + if (fence == prev) return fence; GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)); @@ -1040,27 +1056,56 @@ __i915_active_fence_set(struct i915_active_fence *active, * Consider that we have two threads arriving (A and B), with * C already resident as the active->fence. * - * A does the xchg first, and so it sees C or NULL depending - * on the timing of the interrupt handler. If it is NULL, the - * previous fence must have been signaled and we know that - * we are first on the timeline. If it is still present, - * we acquire the lock on that fence and serialise with the interrupt - * handler, in the process removing it from any future interrupt - * callback. A will then wait on C before executing (if present). - * - * As B is second, it sees A as the previous fence and so waits for - * it to complete its transition and takes over the occupancy for - * itself -- remembering that it needs to wait on A before executing. + * Both A and B have got a reference to C or NULL, depending on the + * timing of the interrupt handler. Let's assume that if A has got C + * then it has locked C first (before B). * * Note the strong ordering of the timeline also provides consistent * nesting rules for the fence->lock; the inner lock is always the * older lock. */ spin_lock_irqsave(fence->lock, flags); - prev = xchg(__active_fence_slot(active), fence); - if (prev) { - GEM_BUG_ON(prev == fence); + if (prev) spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING); + + /* + * A does the cmpxchg first, and so it sees C or NULL, as before, or + * something else, depending on the timing of other threads and/or + * interrupt handler. If not the same as before then A unlocks C if + * applicable and retries, starting from an attempt to get a new + * active->fence. Meanwhile, B follows the same path as A. + * Once A succeeds with cmpxch, B fails again, retires, gets A from + * active->fence, locks it as soon as A completes, and possibly + * succeeds with cmpxchg. + */ + while (cmpxchg(__active_fence_slot(active), prev, fence) != prev) { + if (prev) { + spin_unlock(prev->lock); + dma_fence_put(prev); + } + spin_unlock_irqrestore(fence->lock, flags); + + prev = i915_active_fence_get(active); + GEM_BUG_ON(prev == fence); + + spin_lock_irqsave(fence->lock, flags); + if (prev) + spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING); + } + + /* + * If prev is NULL then the previous fence must have been signaled + * and we know that we are first on the timeline. If it is still + * present then, having the lock on that fence already acquired, we + * serialise with the interrupt handler, in the process of removing it + * from any future interrupt callback. A will then wait on C before + * executing (if present). + * + * As B is second, it sees A as the previous fence and so waits for + * it to complete its transition and takes over the occupancy for + * itself -- remembering that it needs to wait on A before executing. + */ + if (prev) { __list_del_entry(&active->cb.node); spin_unlock(prev->lock); /* serialise with prev->cb_list */ } @@ -1077,11 +1122,7 @@ int i915_active_fence_set(struct i915_active_fence *active, int err = 0; /* Must maintain timeline ordering wrt previous active requests */ - rcu_read_lock(); fence = __i915_active_fence_set(active, &rq->fence); - if (fence) /* but the previous fence may not belong to that timeline! */ - fence = dma_fence_get_rcu(fence); - rcu_read_unlock(); if (fence) { err = i915_request_await_dma_fence(rq, fence); dma_fence_put(fence); diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 894068bb37b6..833b73edefdb 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1661,6 +1661,11 @@ __i915_request_ensure_parallel_ordering(struct i915_request *rq, request_to_parent(rq)->parallel.last_rq = i915_request_get(rq); + /* + * Users have to put a reference potentially got by + * __i915_active_fence_set() to the returned request + * when no longer needed + */ return to_request(__i915_active_fence_set(&timeline->last_request, &rq->fence)); } @@ -1707,6 +1712,10 @@ __i915_request_ensure_ordering(struct i915_request *rq, 0); } + /* + * Users have to put the reference to prev potentially got + * by __i915_active_fence_set() when no longer needed + */ return prev; } @@ -1760,6 +1769,8 @@ __i915_request_add_to_timeline(struct i915_request *rq) prev = __i915_request_ensure_ordering(rq, timeline); else prev = __i915_request_ensure_parallel_ordering(rq, timeline); + if (prev) + i915_request_put(prev); /* * Make sure that no request gazumped us - if it was allocated after -- cgit v1.2.3 From 2dc0bc1138eecc88b2c376ccb0b0acb215c25a5c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 1 Aug 2023 20:26:50 +1000 Subject: powerpc/64e: Fix secondary thread bringup for ELFv2 kernels When booting on e6500 with an ELF v2 ABI kernel, the secondary threads do not start correctly: [ 0.051118] smp: Bringing up secondary CPUs ... [ 5.072700] Processor 1 is stuck. This occurs because the startup code is written to use function descriptors when loading the entry point for the secondary threads. When building with ELF v2 ABI there are no function descriptors, and the code loads junk values for the entry point address. Fix it by using ppc_function_entry() in C, and DOTSYM() in asm, both of which work correctly for ELF v2 ABI as well as ELF v1 ABI kernels. Fixes: 8c5fa3b5c4df ("powerpc/64: Make ELFv2 the default for big-endian builds") Signed-off-by: Michael Ellerman Link: https://msgid.link/20230801102650.48705-1-mpe@ellerman.id.au --- arch/powerpc/kernel/head_64.S | 3 +-- arch/powerpc/platforms/85xx/smp.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index f132d8704263..6440b1bb332a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -375,8 +375,7 @@ _GLOBAL(generic_secondary_smp_init) beq 20f /* start the specified thread */ - LOAD_REG_ADDR(r5, fsl_secondary_thread_init) - ld r4, 0(r5) + LOAD_REG_ADDR(r5, DOTSYM(fsl_secondary_thread_init)) bl book3e_start_thread /* stop the current thread */ diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 9c43cf32f4c9..40aa58206888 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -180,7 +180,7 @@ static void wake_hw_thread(void *info) unsigned long inia; int cpu = *(const int *)info; - inia = *(unsigned long *)fsl_secondary_thread_init; + inia = ppc_function_entry(fsl_secondary_thread_init); book3e_start_thread(cpu_thread_in_core(cpu), inia); } #endif -- cgit v1.2.3 From 16e95a62eed18864aecac404f1e4eed764c363f2 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 25 Jul 2023 13:39:12 +0800 Subject: powercap: intel_rapl: Fix a sparse warning in TPMI interface Depends on the interface used, the RAPL registers can be either MSR indexes or memory mapped IO addresses. Current RAPL common code uses u64 to save both MSR and memory mapped IO registers. With this, when handling register address with an __iomem annotation, it triggers a sparse warning like below: sparse warnings: (new ones prefixed by >>) >> drivers/powercap/intel_rapl_tpmi.c:141:41: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected unsigned long long [usertype] *tpmi_rapl_regs @@ got void [noderef] __iomem * @@ drivers/powercap/intel_rapl_tpmi.c:141:41: sparse: expected unsigned long long [usertype] *tpmi_rapl_regs drivers/powercap/intel_rapl_tpmi.c:141:41: sparse: got void [noderef] __iomem * Fix the problem by using a union to save the registers instead. Suggested-by: David Laight Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307031405.dy3druuy-lkp@intel.com/ Tested-by: Wang Wendy Signed-off-by: Zhang Rui [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl_common.c | 14 +++---- drivers/powercap/intel_rapl_msr.c | 49 +++++++++++----------- drivers/powercap/intel_rapl_tpmi.c | 17 ++++---- .../intel/int340x_thermal/processor_thermal_rapl.c | 16 +++---- include/linux/intel_rapl.h | 14 +++++-- 5 files changed, 58 insertions(+), 52 deletions(-) diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index 4e646e5e48f6..8fac57b28f8a 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -818,7 +818,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd, return -EINVAL; ra.reg = rd->regs[rpi->id]; - if (!ra.reg) + if (!ra.reg.val) return -EINVAL; /* non-hardware data are collected by the polling thread */ @@ -830,7 +830,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd, ra.mask = rpi->mask; if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { - pr_debug("failed to read reg 0x%llx for %s:%s\n", ra.reg, rd->rp->name, rd->name); + pr_debug("failed to read reg 0x%llx for %s:%s\n", ra.reg.val, rd->rp->name, rd->name); return -EIO; } @@ -920,7 +920,7 @@ static int rapl_check_unit_core(struct rapl_domain *rd) ra.mask = ~0; if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", - ra.reg, rd->rp->name, rd->name); + ra.reg.val, rd->rp->name, rd->name); return -ENODEV; } @@ -948,7 +948,7 @@ static int rapl_check_unit_atom(struct rapl_domain *rd) ra.mask = ~0; if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", - ra.reg, rd->rp->name, rd->name); + ra.reg.val, rd->rp->name, rd->name); return -ENODEV; } @@ -1135,7 +1135,7 @@ static int rapl_check_unit_tpmi(struct rapl_domain *rd) ra.mask = ~0; if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra)) { pr_err("Failed to read power unit REG 0x%llx on %s:%s, exit.\n", - ra.reg, rd->rp->name, rd->name); + ra.reg.val, rd->rp->name, rd->name); return -ENODEV; } @@ -1411,8 +1411,8 @@ static int rapl_get_domain_unit(struct rapl_domain *rd) struct rapl_defaults *defaults = get_defaults(rd->rp); int ret; - if (!rd->regs[RAPL_DOMAIN_REG_UNIT]) { - if (!rd->rp->priv->reg_unit) { + if (!rd->regs[RAPL_DOMAIN_REG_UNIT].val) { + if (!rd->rp->priv->reg_unit.val) { pr_err("No valid Unit register found\n"); return -ENODEV; } diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c index 569e25eab1e1..dd471021f237 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c @@ -34,28 +34,32 @@ static struct rapl_if_priv *rapl_msr_priv; static struct rapl_if_priv rapl_msr_priv_intel = { .type = RAPL_IF_MSR, - .reg_unit = MSR_RAPL_POWER_UNIT, - .regs[RAPL_DOMAIN_PACKAGE] = { - MSR_PKG_POWER_LIMIT, MSR_PKG_ENERGY_STATUS, MSR_PKG_PERF_STATUS, 0, MSR_PKG_POWER_INFO }, - .regs[RAPL_DOMAIN_PP0] = { - MSR_PP0_POWER_LIMIT, MSR_PP0_ENERGY_STATUS, 0, MSR_PP0_POLICY, 0 }, - .regs[RAPL_DOMAIN_PP1] = { - MSR_PP1_POWER_LIMIT, MSR_PP1_ENERGY_STATUS, 0, MSR_PP1_POLICY, 0 }, - .regs[RAPL_DOMAIN_DRAM] = { - MSR_DRAM_POWER_LIMIT, MSR_DRAM_ENERGY_STATUS, MSR_DRAM_PERF_STATUS, 0, MSR_DRAM_POWER_INFO }, - .regs[RAPL_DOMAIN_PLATFORM] = { - MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0}, + .reg_unit.msr = MSR_RAPL_POWER_UNIT, + .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PKG_POWER_LIMIT, + .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_STATUS].msr = MSR_PKG_ENERGY_STATUS, + .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PERF].msr = MSR_PKG_PERF_STATUS, + .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_INFO].msr = MSR_PKG_POWER_INFO, + .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PP0_POWER_LIMIT, + .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_STATUS].msr = MSR_PP0_ENERGY_STATUS, + .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_POLICY].msr = MSR_PP0_POLICY, + .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PP1_POWER_LIMIT, + .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_STATUS].msr = MSR_PP1_ENERGY_STATUS, + .regs[RAPL_DOMAIN_PP1][RAPL_DOMAIN_REG_POLICY].msr = MSR_PP1_POLICY, + .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_LIMIT].msr = MSR_DRAM_POWER_LIMIT, + .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_STATUS].msr = MSR_DRAM_ENERGY_STATUS, + .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_PERF].msr = MSR_DRAM_PERF_STATUS, + .regs[RAPL_DOMAIN_DRAM][RAPL_DOMAIN_REG_INFO].msr = MSR_DRAM_POWER_INFO, + .regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT].msr = MSR_PLATFORM_POWER_LIMIT, + .regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS].msr = MSR_PLATFORM_ENERGY_STATUS, .limits[RAPL_DOMAIN_PACKAGE] = BIT(POWER_LIMIT2), .limits[RAPL_DOMAIN_PLATFORM] = BIT(POWER_LIMIT2), }; static struct rapl_if_priv rapl_msr_priv_amd = { .type = RAPL_IF_MSR, - .reg_unit = MSR_AMD_RAPL_POWER_UNIT, - .regs[RAPL_DOMAIN_PACKAGE] = { - 0, MSR_AMD_PKG_ENERGY_STATUS, 0, 0, 0 }, - .regs[RAPL_DOMAIN_PP0] = { - 0, MSR_AMD_CORE_ENERGY_STATUS, 0, 0, 0 }, + .reg_unit.msr = MSR_AMD_RAPL_POWER_UNIT, + .regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_STATUS].msr = MSR_AMD_PKG_ENERGY_STATUS, + .regs[RAPL_DOMAIN_PP0][RAPL_DOMAIN_REG_STATUS].msr = MSR_AMD_CORE_ENERGY_STATUS, }; /* Handles CPU hotplug on multi-socket systems. @@ -99,10 +103,8 @@ static int rapl_cpu_down_prep(unsigned int cpu) static int rapl_msr_read_raw(int cpu, struct reg_action *ra) { - u32 msr = (u32)ra->reg; - - if (rdmsrl_safe_on_cpu(cpu, msr, &ra->value)) { - pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu); + if (rdmsrl_safe_on_cpu(cpu, ra->reg.msr, &ra->value)) { + pr_debug("failed to read msr 0x%x on cpu %d\n", ra->reg.msr, cpu); return -EIO; } ra->value &= ra->mask; @@ -112,17 +114,16 @@ static int rapl_msr_read_raw(int cpu, struct reg_action *ra) static void rapl_msr_update_func(void *info) { struct reg_action *ra = info; - u32 msr = (u32)ra->reg; u64 val; - ra->err = rdmsrl_safe(msr, &val); + ra->err = rdmsrl_safe(ra->reg.msr, &val); if (ra->err) return; val &= ~ra->mask; val |= ra->value; - ra->err = wrmsrl_safe(msr, val); + ra->err = wrmsrl_safe(ra->reg.msr, val); } static int rapl_msr_write_raw(int cpu, struct reg_action *ra) @@ -171,7 +172,7 @@ static int rapl_msr_probe(struct platform_device *pdev) if (id) { rapl_msr_priv->limits[RAPL_DOMAIN_PACKAGE] |= BIT(POWER_LIMIT4); - rapl_msr_priv->regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4] = + rapl_msr_priv->regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4].msr = MSR_VR_CURRENT_CONFIG; pr_info("PL4 support detected.\n"); } diff --git a/drivers/powercap/intel_rapl_tpmi.c b/drivers/powercap/intel_rapl_tpmi.c index 4f4f13ded225..891c90fefd8b 100644 --- a/drivers/powercap/intel_rapl_tpmi.c +++ b/drivers/powercap/intel_rapl_tpmi.c @@ -59,10 +59,10 @@ static struct powercap_control_type *tpmi_control_type; static int tpmi_rapl_read_raw(int id, struct reg_action *ra) { - if (!ra->reg) + if (!ra->reg.mmio) return -EINVAL; - ra->value = readq((void __iomem *)ra->reg); + ra->value = readq(ra->reg.mmio); ra->value &= ra->mask; return 0; @@ -72,15 +72,15 @@ static int tpmi_rapl_write_raw(int id, struct reg_action *ra) { u64 val; - if (!ra->reg) + if (!ra->reg.mmio) return -EINVAL; - val = readq((void __iomem *)ra->reg); + val = readq(ra->reg.mmio); val &= ~ra->mask; val |= ra->value; - writeq(val, (void __iomem *)ra->reg); + writeq(val, ra->reg.mmio); return 0; } @@ -138,8 +138,7 @@ static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset) enum tpmi_rapl_register reg_index; enum rapl_domain_reg_id reg_id; int tpmi_domain_size, tpmi_domain_flags; - u64 *tpmi_rapl_regs = trp->base + offset; - u64 tpmi_domain_header = readq((void __iomem *)tpmi_rapl_regs); + u64 tpmi_domain_header = readq(trp->base + offset); /* Domain Parent bits are ignored for now */ tpmi_domain_version = tpmi_domain_header & 0xff; @@ -180,7 +179,7 @@ static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset) return -EINVAL; } - if (trp->priv.regs[domain_type][RAPL_DOMAIN_REG_UNIT]) { + if (trp->priv.regs[domain_type][RAPL_DOMAIN_REG_UNIT].mmio) { pr_warn(FW_BUG "Duplicate Domain type %d\n", tpmi_domain_type); return -EINVAL; } @@ -218,7 +217,7 @@ static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset) default: continue; } - trp->priv.regs[domain_type][reg_id] = (u64)&tpmi_rapl_regs[reg_index]; + trp->priv.regs[domain_type][reg_id].mmio = trp->base + offset + reg_index * 8; } return 0; diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c index 013f1633f082..2f00fc3bf274 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c @@ -57,10 +57,10 @@ static int rapl_mmio_cpu_down_prep(unsigned int cpu) static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) { - if (!ra->reg) + if (!ra->reg.mmio) return -EINVAL; - ra->value = readq((void __iomem *)ra->reg); + ra->value = readq(ra->reg.mmio); ra->value &= ra->mask; return 0; } @@ -69,13 +69,13 @@ static int rapl_mmio_write_raw(int cpu, struct reg_action *ra) { u64 val; - if (!ra->reg) + if (!ra->reg.mmio) return -EINVAL; - val = readq((void __iomem *)ra->reg); + val = readq(ra->reg.mmio); val &= ~ra->mask; val |= ra->value; - writeq(val, (void __iomem *)ra->reg); + writeq(val, ra->reg.mmio); return 0; } @@ -92,13 +92,13 @@ int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) { for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++) if (rapl_regs->regs[domain][reg]) - rapl_mmio_priv.regs[domain][reg] = - (u64)proc_priv->mmio_base + + rapl_mmio_priv.regs[domain][reg].mmio = + proc_priv->mmio_base + rapl_regs->regs[domain][reg]; rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain]; } rapl_mmio_priv.type = RAPL_IF_MMIO; - rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit; + rapl_mmio_priv.reg_unit.mmio = proc_priv->mmio_base + rapl_regs->reg_unit; rapl_mmio_priv.read_raw = rapl_mmio_read_raw; rapl_mmio_priv.write_raw = rapl_mmio_write_raw; diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h index e6936cb25047..33f21bd85dbf 100644 --- a/include/linux/intel_rapl.h +++ b/include/linux/intel_rapl.h @@ -100,10 +100,16 @@ struct rapl_package; #define RAPL_DOMAIN_NAME_LENGTH 16 +union rapl_reg { + void __iomem *mmio; + u32 msr; + u64 val; +}; + struct rapl_domain { char name[RAPL_DOMAIN_NAME_LENGTH]; enum rapl_domain_type id; - u64 regs[RAPL_DOMAIN_REG_MAX]; + union rapl_reg regs[RAPL_DOMAIN_REG_MAX]; struct powercap_zone power_zone; struct rapl_domain_data rdd; struct rapl_power_limit rpl[NR_POWER_LIMITS]; @@ -116,7 +122,7 @@ struct rapl_domain { }; struct reg_action { - u64 reg; + union rapl_reg reg; u64 mask; u64 value; int err; @@ -143,8 +149,8 @@ struct rapl_if_priv { enum rapl_if_type type; struct powercap_control_type *control_type; enum cpuhp_state pcap_rapl_online; - u64 reg_unit; - u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; + union rapl_reg reg_unit; + union rapl_reg regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; int limits[RAPL_DOMAIN_MAX]; int (*read_raw)(int id, struct reg_action *ra); int (*write_raw)(int id, struct reg_action *ra); -- cgit v1.2.3 From 1d7dd5aa35474e553b8671b58579e0749b560779 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 28 Jul 2023 16:13:02 -0700 Subject: wifi: ray_cs: Replace 1-element array with flexible array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trailing array member of struct tx_buf was defined as a 1-element array, but used as a flexible array. This was resulting in build warnings: In function 'fortify_memset_chk', inlined from 'memset_io' at /kisskb/src/arch/mips/include/asm/io.h:486:2, inlined from 'build_auth_frame' at /kisskb/src/drivers/net/wireless/legacy/ray_cs.c:2697:2: /kisskb/src/include/linux/fortify-string.h:493:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] 493 | __write_overflow_field(p_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Replace it with an actual flexible array. Binary difference comparison shows a single change in output: │ drivers/net/wireless/legacy/ray_cs.c:883 │ lea 0x1c(%rbp),%r13d │ - cmp $0x7c3,%r13d │ + cmp $0x7c4,%r13d This is from: if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { specifically: #define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) This appears to have been originally buggy, so the change is correct. Reported-by: Geert Uytterhoeven Closes: https://lore.kernel.org/all/88f83d73-781d-bdc-126-aa629cb368c@linux-m68k.org Cc: Kalle Valo Cc: linux-wireless@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230728231245.never.309-kees@kernel.org --- drivers/net/wireless/legacy/rayctl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h index 2b0f332043d7..1f3bde8ac73d 100644 --- a/drivers/net/wireless/legacy/rayctl.h +++ b/drivers/net/wireless/legacy/rayctl.h @@ -577,7 +577,7 @@ struct tx_msg { struct tib_structure tib; struct phy_header phy; struct mac_header mac; - UCHAR var[1]; + UCHAR var[]; }; /****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */ -- cgit v1.2.3 From 388acb471662c273d94163a8502f09668f380686 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Jul 2023 20:39:26 +0200 Subject: s390/ptrace: add missing linux/const.h include Adrian Reber reported the following CRIU build bug after commit b8af5999779d ("s390/ptrace: make all psw related defines also available for asm"): compel/arch/s390/src/lib/infect.c: In function 'arch_can_dump_task': compel/arch/s390/src/lib/infect.c:523:25: error: 'UL' undeclared (first use in this function) 523 | if (psw->mask & PSW_MASK_RI) { | ^~~~~~~~~~~ Add the missing linux/const.h include to fix this. Reported-by: Adrian Reber Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2225745 Link: https://github.com/checkpoint-restore/criu/pull/2232 Tested-by: Adrian Reber Fixes: b8af5999779d ("s390/ptrace: make all psw related defines also available for asm") Link: https://lore.kernel.org/r/20230731183926.330932-1-hca@linux.ibm.com Signed-off-by: Heiko Carstens --- arch/s390/include/uapi/asm/ptrace.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h index f0fe3bcc78a8..bb0826024bb9 100644 --- a/arch/s390/include/uapi/asm/ptrace.h +++ b/arch/s390/include/uapi/asm/ptrace.h @@ -8,6 +8,8 @@ #ifndef _UAPI_S390_PTRACE_H #define _UAPI_S390_PTRACE_H +#include + /* * Offsets in the user_regs_struct. They are used for the ptrace * system call and in entry.S -- cgit v1.2.3 From 688b419c57c13637d95d7879e165fff3dec581eb Mon Sep 17 00:00:00 2001 From: August Wikerfors Date: Wed, 16 Nov 2022 18:17:27 +0100 Subject: nvme-pci: add NVME_QUIRK_BOGUS_NID for Samsung PM9B1 256G and 512G The Samsung PM9B1 512G SSD found in some Lenovo Yoga 7 14ARB7 laptop units reports eui as 0001000200030004 when resuming from s2idle, causing the device to be removed with this error in dmesg: nvme nvme0: identifiers changed for nsid 1 To fix this, add a quirk to ignore namespace identifiers for this device. Signed-off-by: August Wikerfors Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index baf69af7ea78..2f57da12d983 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3402,7 +3402,8 @@ static const struct pci_device_id nvme_id_table[] = { { PCI_DEVICE(0x1d97, 0x2263), /* SPCC */ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, { PCI_DEVICE(0x144d, 0xa80b), /* Samsung PM9B1 256G and 512G */ - .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, + .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES | + NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x144d, 0xa809), /* Samsung MZALQ256HBJD 256G */ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, { PCI_DEVICE(0x144d, 0xa802), /* Samsung SM953 */ -- cgit v1.2.3 From ef45e8400f5bb66b03cc949f76c80e2a118447de Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 31 Jul 2023 10:42:32 +0300 Subject: net: ll_temac: fix error checking of irq_of_parse_and_map() Most kernel functions return negative error codes but some irq functions return zero on error. In this code irq_of_parse_and_map(), returns zero and platform_get_irq() returns negative error codes. We need to handle both cases appropriately. Fixes: 8425c41d1ef7 ("net: ll_temac: Extend support to non-device-tree platforms") Signed-off-by: Dan Carpenter Acked-by: Esben Haabendal Reviewed-by: Yang Yingliang Reviewed-by: Harini Katakam Link: https://lore.kernel.org/r/3d0aef75-06e0-45a5-a2a6-2cc4738d4143@moroto.mountain Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/ll_temac_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index e0ac1bcd9925..49f303353ecb 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -1567,12 +1567,16 @@ static int temac_probe(struct platform_device *pdev) } /* Error handle returned DMA RX and TX interrupts */ - if (lp->rx_irq < 0) - return dev_err_probe(&pdev->dev, lp->rx_irq, + if (lp->rx_irq <= 0) { + rc = lp->rx_irq ?: -EINVAL; + return dev_err_probe(&pdev->dev, rc, "could not get DMA RX irq\n"); - if (lp->tx_irq < 0) - return dev_err_probe(&pdev->dev, lp->tx_irq, + } + if (lp->tx_irq <= 0) { + rc = lp->tx_irq ?: -EINVAL; + return dev_err_probe(&pdev->dev, rc, "could not get DMA TX irq\n"); + } if (temac_np) { /* Retrieve the MAC address */ -- cgit v1.2.3 From b99225b4fe297d07400f9e2332ecd7347b224f8d Mon Sep 17 00:00:00 2001 From: Ross Maynard Date: Mon, 31 Jul 2023 15:42:04 +1000 Subject: USB: zaurus: Add ID for A-300/B-500/C-700 The SL-A300, B500/5600, and C700 devices no longer auto-load because of "usbnet: Remove over-broad module alias from zaurus." This patch adds IDs for those 3 devices. Link: https://bugzilla.kernel.org/show_bug.cgi?id=217632 Fixes: 16adf5d07987 ("usbnet: Remove over-broad module alias from zaurus.") Signed-off-by: Ross Maynard Cc: stable@vger.kernel.org Acked-by: Greg Kroah-Hartman Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/69b5423b-2013-9fc9-9569-58e707d9bafb@bigpond.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/cdc_ether.c | 21 +++++++++++++++++++++ drivers/net/usb/zaurus.c | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index c00a89b24df9..6d61052353f0 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -618,9 +618,23 @@ static const struct usb_device_id products[] = { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, + .idProduct = 0x8005, /* A-300 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, .idProduct = 0x8006, /* B-500/SL-5600 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8006, /* B-500/SL-5600 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = 0, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, @@ -628,6 +642,13 @@ static const struct usb_device_id products[] = { .idProduct = 0x8007, /* C-700 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8007, /* C-700 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = 0, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 7984f2157d22..df3617c4c44e 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -289,9 +289,23 @@ static const struct usb_device_id products [] = { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, + .idProduct = 0x8005, /* A-300 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = (unsigned long)&bogus_mdlm_info, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, .idProduct = 0x8006, /* B-500/SL-5600 */ ZAURUS_MASTER_INTERFACE, .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8006, /* B-500/SL-5600 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = (unsigned long)&bogus_mdlm_info, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, @@ -299,6 +313,13 @@ static const struct usb_device_id products [] = { .idProduct = 0x8007, /* C-700 */ ZAURUS_MASTER_INTERFACE, .driver_info = ZAURUS_PXA_INFO, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x8007, /* C-700 */ + ZAURUS_FAKE_INTERFACE, + .driver_info = (unsigned long)&bogus_mdlm_info, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, -- cgit v1.2.3 From 0b6291ad1940c403734312d0e453e8dac9148f69 Mon Sep 17 00:00:00 2001 From: Yuanjun Gong Date: Mon, 31 Jul 2023 17:05:35 +0800 Subject: net: korina: handle clk prepare error in korina_probe() in korina_probe(), the return value of clk_prepare_enable() should be checked since it might fail. we can use devm_clk_get_optional_enabled() instead of devm_clk_get_optional() and clk_prepare_enable() to automatically handle the error. Fixes: e4cd854ec487 ("net: korina: Get mdio input clock via common clock framework") Signed-off-by: Yuanjun Gong Link: https://lore.kernel.org/r/20230731090535.21416-1-ruc_gongyuanjun@163.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/korina.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 2b9335cb4bb3..8537578e1cf1 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -1302,11 +1302,10 @@ static int korina_probe(struct platform_device *pdev) else if (of_get_ethdev_address(pdev->dev.of_node, dev) < 0) eth_hw_addr_random(dev); - clk = devm_clk_get_optional(&pdev->dev, "mdioclk"); + clk = devm_clk_get_optional_enabled(&pdev->dev, "mdioclk"); if (IS_ERR(clk)) return PTR_ERR(clk); if (clk) { - clk_prepare_enable(clk); lp->mii_clock_freq = clk_get_rate(clk); } else { lp->mii_clock_freq = 200000000; /* max possible input clk */ -- cgit v1.2.3 From f3bb7759a924713bc54d15f6d0d70733b5935fad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 11:48:32 +0100 Subject: net: netsec: Ignore 'phy-mode' on SynQuacer in DT mode As documented in acd7aaf51b20 ("netsec: ignore 'phy-mode' device property on ACPI systems") the SocioNext SynQuacer platform ships with firmware defining the PHY mode as RGMII even though the physical configuration of the PHY is for TX and RX delays. Since bbc4d71d63549bc ("net: phy: realtek: fix rtl8211e rx/tx delay config") this has caused misconfiguration of the PHY, rendering the network unusable. This was worked around for ACPI by ignoring the phy-mode property but the system is also used with DT. For DT instead if we're running on a SynQuacer force a working PHY mode, as well as the standard EDK2 firmware with DT there are also some of these systems that use u-boot and might not initialise the PHY if not netbooting. Newer firmware imagaes for at least EDK2 are available from Linaro so print a warning when doing this. Fixes: 533dd11a12f6 ("net: socionext: Add Synquacer NetSec driver") Signed-off-by: Mark Brown Acked-by: Ard Biesheuvel Acked-by: Ilias Apalodimas Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230731-synquacer-net-v3-1-944be5f06428@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/socionext/netsec.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 2d7347b71c41..0dcd6a568b06 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -1851,6 +1851,17 @@ static int netsec_of_probe(struct platform_device *pdev, return err; } + /* + * SynQuacer is physically configured with TX and RX delays + * but the standard firmware claimed otherwise for a long + * time, ignore it. + */ + if (of_machine_is_compatible("socionext,developer-box") && + priv->phy_interface != PHY_INTERFACE_MODE_RGMII_ID) { + dev_warn(&pdev->dev, "Outdated firmware reports incorrect PHY mode, overriding\n"); + priv->phy_interface = PHY_INTERFACE_MODE_RGMII_ID; + } + priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); if (!priv->phy_np) { dev_err(&pdev->dev, "missing required property 'phy-handle'\n"); -- cgit v1.2.3 From 3ff1617450eceb290ac17120fc172815e09a93cf Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 31 Jul 2023 11:15:53 -0700 Subject: selftest: net: Assert on a proper value in so_incoming_cpu.c. Dan Carpenter reported an error spotted by Smatch. ./tools/testing/selftests/net/so_incoming_cpu.c:163 create_clients() error: uninitialized symbol 'ret'. The returned value of sched_setaffinity() should be checked with ASSERT_EQ(), but the value was not saved in a proper variable, resulting in an error above. Let's save the returned value of with sched_setaffinity(). Fixes: 6df96146b202 ("selftest: Add test for SO_INCOMING_CPU.") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-kselftest/fe376760-33b6-4fc9-88e8-178e809af1ac@moroto.mountain/ Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230731181553.5392-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/so_incoming_cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/so_incoming_cpu.c b/tools/testing/selftests/net/so_incoming_cpu.c index 0e04f9fef986..a14818164102 100644 --- a/tools/testing/selftests/net/so_incoming_cpu.c +++ b/tools/testing/selftests/net/so_incoming_cpu.c @@ -159,7 +159,7 @@ void create_clients(struct __test_metadata *_metadata, /* Make sure SYN will be processed on the i-th CPU * and finally distributed to the i-th listener. */ - sched_setaffinity(0, sizeof(cpu_set), &cpu_set); + ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set); ASSERT_EQ(ret, 0); for (j = 0; j < CLIENT_PER_SERVER; j++) { -- cgit v1.2.3 From f6974b4c2d8e1062b5a52228ee47293c15b4ee1e Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Mon, 31 Jul 2023 07:20:42 -0700 Subject: bnxt_en: Fix page pool logic for page size >= 64K The RXBD length field on all bnxt chips is 16-bit and so we cannot support a full page when the native page size is 64K or greater. The non-XDP (non page pool) code path has logic to handle this but the XDP page pool code path does not handle this. Add the missing logic to use page_pool_dev_alloc_frag() to allocate 32K chunks if the page size is 64K or greater. Fixes: 9f4b28301ce6 ("bnxt: XDP multibuffer enablement") Link: https://lore.kernel.org/netdev/20230728231829.235716-2-michael.chan@broadcom.com/ Reviewed-by: Andy Gospodarek Signed-off-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20230731142043.58855-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 42 +++++++++++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 6 ++-- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 06b238bef9dd..4d36de6915a0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -699,17 +699,24 @@ next_tx_int: static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, struct bnxt_rx_ring_info *rxr, + unsigned int *offset, gfp_t gfp) { struct device *dev = &bp->pdev->dev; struct page *page; - page = page_pool_dev_alloc_pages(rxr->page_pool); + if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) { + page = page_pool_dev_alloc_frag(rxr->page_pool, offset, + BNXT_RX_PAGE_SIZE); + } else { + page = page_pool_dev_alloc_pages(rxr->page_pool); + *offset = 0; + } if (!page) return NULL; - *mapping = dma_map_page_attrs(dev, page, 0, PAGE_SIZE, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); + *mapping = dma_map_page_attrs(dev, page, *offset, BNXT_RX_PAGE_SIZE, + bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(dev, *mapping)) { page_pool_recycle_direct(rxr->page_pool, page); return NULL; @@ -749,15 +756,16 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, dma_addr_t mapping; if (BNXT_RX_PAGE_MODE(bp)) { + unsigned int offset; struct page *page = - __bnxt_alloc_rx_page(bp, &mapping, rxr, gfp); + __bnxt_alloc_rx_page(bp, &mapping, rxr, &offset, gfp); if (!page) return -ENOMEM; mapping += bp->rx_dma_offset; rx_buf->data = page; - rx_buf->data_ptr = page_address(page) + bp->rx_offset; + rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset; } else { u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, gfp); @@ -817,7 +825,7 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, unsigned int offset = 0; if (BNXT_RX_PAGE_MODE(bp)) { - page = __bnxt_alloc_rx_page(bp, &mapping, rxr, gfp); + page = __bnxt_alloc_rx_page(bp, &mapping, rxr, &offset, gfp); if (!page) return -ENOMEM; @@ -964,15 +972,15 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp, return NULL; } dma_addr -= bp->rx_dma_offset; - dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); - skb = build_skb(page_address(page), PAGE_SIZE); + dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE, + bp->rx_dir, DMA_ATTR_WEAK_ORDERING); + skb = build_skb(data_ptr - bp->rx_offset, BNXT_RX_PAGE_SIZE); if (!skb) { page_pool_recycle_direct(rxr->page_pool, page); return NULL; } skb_mark_for_recycle(skb); - skb_reserve(skb, bp->rx_dma_offset); + skb_reserve(skb, bp->rx_offset); __skb_put(skb, len); return skb; @@ -998,8 +1006,8 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp, return NULL; } dma_addr -= bp->rx_dma_offset; - dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); + dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE, + bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (unlikely(!payload)) payload = eth_get_headlen(bp->dev, data_ptr, len); @@ -1012,7 +1020,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp, skb_mark_for_recycle(skb); off = (void *)data_ptr - page_address(page); - skb_add_rx_frag(skb, 0, page, off, len, PAGE_SIZE); + skb_add_rx_frag(skb, 0, page, off, len, BNXT_RX_PAGE_SIZE); memcpy(skb->data - NET_IP_ALIGN, data_ptr - NET_IP_ALIGN, payload + NET_IP_ALIGN); @@ -1143,7 +1151,7 @@ static struct sk_buff *bnxt_rx_agg_pages_skb(struct bnxt *bp, skb->data_len += total_frag_len; skb->len += total_frag_len; - skb->truesize += PAGE_SIZE * agg_bufs; + skb->truesize += BNXT_RX_PAGE_SIZE * agg_bufs; return skb; } @@ -2945,8 +2953,8 @@ skip_rx_tpa_free: rx_buf->data = NULL; if (BNXT_RX_PAGE_MODE(bp)) { mapping -= bp->rx_dma_offset; - dma_unmap_page_attrs(&pdev->dev, mapping, PAGE_SIZE, - bp->rx_dir, + dma_unmap_page_attrs(&pdev->dev, mapping, + BNXT_RX_PAGE_SIZE, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); page_pool_recycle_direct(rxr->page_pool, data); } else { @@ -3215,6 +3223,8 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp, pp.napi = &rxr->bnapi->napi; pp.dev = &bp->pdev->dev; pp.dma_dir = DMA_BIDIRECTIONAL; + if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) + pp.flags |= PP_FLAG_PAGE_FRAG; rxr->page_pool = page_pool_create(&pp); if (IS_ERR(rxr->page_pool)) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 7f2f9a317d47..fb43232310b2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -186,8 +186,8 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, u8 *data_ptr, unsigned int len, struct xdp_buff *xdp) { + u32 buflen = BNXT_RX_PAGE_SIZE; struct bnxt_sw_rx_bd *rx_buf; - u32 buflen = PAGE_SIZE; struct pci_dev *pdev; dma_addr_t mapping; u32 offset; @@ -303,7 +303,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, rx_buf = &rxr->rx_buf_ring[cons]; mapping = rx_buf->mapping - bp->rx_dma_offset; dma_unmap_page_attrs(&pdev->dev, mapping, - PAGE_SIZE, bp->rx_dir, + BNXT_RX_PAGE_SIZE, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); /* if we are unable to allocate a new buffer, abort and reuse */ @@ -486,7 +486,7 @@ bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb, u8 num_frags, } xdp_update_skb_shared_info(skb, num_frags, sinfo->xdp_frags_size, - PAGE_SIZE * sinfo->nr_frags, + BNXT_RX_PAGE_SIZE * sinfo->nr_frags, xdp_buff_is_frag_pfmemalloc(xdp)); return skb; } -- cgit v1.2.3 From 08450ea98ae98d5a35145b675b76db616046ea11 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 31 Jul 2023 07:20:43 -0700 Subject: bnxt_en: Fix max_mtu setting for multi-buf XDP The existing code does not allow the MTU to be set to the maximum even after an XDP program supporting multiple buffers is attached. Fix it to set the netdev->max_mtu to the maximum value if the attached XDP program supports mutiple buffers, regardless of the current MTU value. Also use a local variable dev instead of repeatedly using bp->dev. Fixes: 1dc4c557bfed ("bnxt: adding bnxt_xdp_build_skb to build skb from multibuffer xdp_buff") Reviewed-by: Somnath Kotur Reviewed-by: Ajit Khaparde Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20230731142043.58855-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4d36de6915a0..1eb490c48c52 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4001,26 +4001,29 @@ void bnxt_set_ring_params(struct bnxt *bp) */ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode) { + struct net_device *dev = bp->dev; + if (page_mode) { bp->flags &= ~BNXT_FLAG_AGG_RINGS; bp->flags |= BNXT_FLAG_RX_PAGE_MODE; - if (bp->dev->mtu > BNXT_MAX_PAGE_MODE_MTU) { + if (bp->xdp_prog->aux->xdp_has_frags) + dev->max_mtu = min_t(u16, bp->max_mtu, BNXT_MAX_MTU); + else + dev->max_mtu = + min_t(u16, bp->max_mtu, BNXT_MAX_PAGE_MODE_MTU); + if (dev->mtu > BNXT_MAX_PAGE_MODE_MTU) { bp->flags |= BNXT_FLAG_JUMBO; bp->rx_skb_func = bnxt_rx_multi_page_skb; - bp->dev->max_mtu = - min_t(u16, bp->max_mtu, BNXT_MAX_MTU); } else { bp->flags |= BNXT_FLAG_NO_AGG_RINGS; bp->rx_skb_func = bnxt_rx_page_skb; - bp->dev->max_mtu = - min_t(u16, bp->max_mtu, BNXT_MAX_PAGE_MODE_MTU); } bp->rx_dir = DMA_BIDIRECTIONAL; /* Disable LRO or GRO_HW */ - netdev_update_features(bp->dev); + netdev_update_features(dev); } else { - bp->dev->max_mtu = bp->max_mtu; + dev->max_mtu = bp->max_mtu; bp->flags &= ~BNXT_FLAG_RX_PAGE_MODE; bp->rx_dir = DMA_FROM_DEVICE; bp->rx_skb_func = bnxt_rx_skb; -- cgit v1.2.3 From e7e607bd00481745550389a29ecabe33e13d67cf Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 25 Jul 2023 12:03:59 +0800 Subject: ceph: defer stopping mdsc delayed_work Flushing the dirty buffer may take a long time if the cluster is overloaded or if there is network issue. So we should ping the MDSs periodically to keep alive, else the MDS will blocklist the kclient. Cc: stable@vger.kernel.org Link: https://tracker.ceph.com/issues/61843 Signed-off-by: Xiubo Li Reviewed-by: Milind Changire Signed-off-by: Ilya Dryomov --- fs/ceph/mds_client.c | 4 ++-- fs/ceph/mds_client.h | 5 +++++ fs/ceph/super.c | 10 ++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 66048a86c480..5fb367b1d4b0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -4764,7 +4764,7 @@ static void delayed_work(struct work_struct *work) dout("mdsc delayed_work\n"); - if (mdsc->stopping) + if (mdsc->stopping >= CEPH_MDSC_STOPPING_FLUSHED) return; mutex_lock(&mdsc->mutex); @@ -4943,7 +4943,7 @@ void send_flush_mdlog(struct ceph_mds_session *s) void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) { dout("pre_umount\n"); - mdsc->stopping = 1; + mdsc->stopping = CEPH_MDSC_STOPPING_BEGIN; ceph_mdsc_iterate_sessions(mdsc, send_flush_mdlog, true); ceph_mdsc_iterate_sessions(mdsc, lock_unlock_session, false); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 724307ff89cd..86d2965e68a1 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -380,6 +380,11 @@ struct cap_wait { int want; }; +enum { + CEPH_MDSC_STOPPING_BEGIN = 1, + CEPH_MDSC_STOPPING_FLUSHED = 2, +}; + /* * mds client state */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 3fc48b43cab0..a5f52013314d 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -1374,6 +1374,16 @@ static void ceph_kill_sb(struct super_block *s) ceph_mdsc_pre_umount(fsc->mdsc); flush_fs_workqueues(fsc); + /* + * Though the kill_anon_super() will finally trigger the + * sync_filesystem() anyway, we still need to do it here + * and then bump the stage of shutdown to stop the work + * queue as earlier as possible. + */ + sync_filesystem(s); + + fsc->mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHED; + kill_anon_super(s); fsc->client->extra_mon_dispatch = NULL; -- cgit v1.2.3 From 1b0fc0345f2852ffe54fb9ae0e12e2ee69ad6a20 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Tue, 1 Aug 2023 07:31:07 -0700 Subject: Documentation/x86: Fix backwards on/off logic about YMM support These options clearly turn *off* XSAVE YMM support. Correct the typo. Reported-by: Ben Hutchings Fixes: 553a5c03e90a ("x86/speculation: Add force option to GDS mitigation") Signed-off-by: Dave Hansen --- Documentation/admin-guide/hw-vuln/gather_data_sampling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst index 40b7a6260010..264bfa937f7d 100644 --- a/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst +++ b/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst @@ -63,7 +63,7 @@ GDS can also be mitigated on systems that don't have updated microcode by disabling AVX. This can be done by setting gather_data_sampling="force" or "clearcpuid=avx" on the kernel command-line. -If used, these options will disable AVX use by turning on XSAVE YMM support. +If used, these options will disable AVX use by turning off XSAVE YMM support. However, the processor will still enumerate AVX support. Userspace that does not follow proper AVX enumeration to check both AVX *and* XSAVE YMM support will break. -- cgit v1.2.3 From 31d49ba033095f6e8158c60f69714a500922e0c3 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Tue, 1 Aug 2023 09:32:48 +0800 Subject: net: dcb: choose correct policy to parse DCB_ATTR_BCN The dcbnl_bcn_setcfg uses erroneous policy to parse tb[DCB_ATTR_BCN], which is introduced in commit 859ee3c43812 ("DCB: Add support for DCB BCN"). Please see the comment in below code static int dcbnl_bcn_setcfg(...) { ... ret = nla_parse_nested_deprecated(..., dcbnl_pfc_up_nest, .. ) // !!! dcbnl_pfc_up_nest for attributes // DCB_PFC_UP_ATTR_0 to DCB_PFC_UP_ATTR_ALL in enum dcbnl_pfc_up_attrs ... for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { // !!! DCB_BCN_ATTR_RP_0 to DCB_BCN_ATTR_RP_7 in enum dcbnl_bcn_attrs ... value_byte = nla_get_u8(data[i]); ... } ... for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { // !!! DCB_BCN_ATTR_BCNA_0 to DCB_BCN_ATTR_RI in enum dcbnl_bcn_attrs ... value_int = nla_get_u32(data[i]); ... } ... } That is, the nla_parse_nested_deprecated uses dcbnl_pfc_up_nest attributes to parse nlattr defined in dcbnl_pfc_up_attrs. But the following access code fetch each nlattr as dcbnl_bcn_attrs attributes. By looking up the associated nla_policy for dcbnl_bcn_attrs. We can find the beginning part of these two policies are "same". static const struct nla_policy dcbnl_pfc_up_nest[...] = { [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, }; static const struct nla_policy dcbnl_bcn_nest[...] = { [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, // from here is somewhat different [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, ... [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, }; Therefore, the current code is buggy and this nla_parse_nested_deprecated could overflow the dcbnl_pfc_up_nest and use the adjacent nla_policy to parse attributes from DCB_BCN_ATTR_BCNA_0. Hence use the correct policy dcbnl_bcn_nest to parse the nested tb[DCB_ATTR_BCN] TLV. Fixes: 859ee3c43812 ("DCB: Add support for DCB BCN") Signed-off-by: Lin Ma Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230801013248.87240-1-linma@zju.edu.cn Signed-off-by: Jakub Kicinski --- net/dcb/dcbnl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index c0c438128575..2e6b8c8fd2de 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -980,7 +980,7 @@ static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, return -EOPNOTSUPP; ret = nla_parse_nested_deprecated(data, DCB_BCN_ATTR_MAX, - tb[DCB_ATTR_BCN], dcbnl_pfc_up_nest, + tb[DCB_ATTR_BCN], dcbnl_bcn_nest, NULL); if (ret) return ret; -- cgit v1.2.3 From 9d01e07fd1bfb4daae156ab528aa196f5ac2b2bc Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 1 Aug 2023 19:14:24 +0200 Subject: rbd: prevent busy loop when requesting exclusive lock Due to rbd_try_acquire_lock() effectively swallowing all but EBLOCKLISTED error from rbd_try_lock() ("request lock anyway") and rbd_request_lock() returning ETIMEDOUT error not only for an actual notify timeout but also when the lock owner doesn't respond, a busy loop inside of rbd_acquire_lock() between rbd_try_acquire_lock() and rbd_request_lock() is possible. Requesting the lock on EBUSY error (returned by get_lock_owner_info() if an incompatible lock or invalid lock owner is detected) makes very little sense. The same goes for ETIMEDOUT error (might pop up pretty much anywhere if osd_request_timeout option is set) and many others. Just fail I/O requests on rbd_dev->acquiring_list immediately on any error from rbd_try_lock(). Cc: stable@vger.kernel.org # 588159009d5b: rbd: retrieve and check lock owner twice before blocklisting Cc: stable@vger.kernel.org Signed-off-by: Ilya Dryomov Reviewed-by: Dongsheng Yang --- drivers/block/rbd.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 24afcc93ac01..2328cc05be36 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3675,7 +3675,7 @@ static int rbd_lock(struct rbd_device *rbd_dev) ret = ceph_cls_lock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, RBD_LOCK_NAME, CEPH_CLS_LOCK_EXCLUSIVE, cookie, RBD_LOCK_TAG, "", 0); - if (ret) + if (ret && ret != -EEXIST) return ret; __rbd_lock(rbd_dev, cookie); @@ -3878,7 +3878,7 @@ static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev) &rbd_dev->header_oloc, RBD_LOCK_NAME, &lock_type, &lock_tag, &lockers, &num_lockers); if (ret) { - rbd_warn(rbd_dev, "failed to retrieve lockers: %d", ret); + rbd_warn(rbd_dev, "failed to get header lockers: %d", ret); return ERR_PTR(ret); } @@ -3940,8 +3940,10 @@ static int find_watcher(struct rbd_device *rbd_dev, ret = ceph_osdc_list_watchers(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, &watchers, &num_watchers); - if (ret) + if (ret) { + rbd_warn(rbd_dev, "failed to get watchers: %d", ret); return ret; + } sscanf(locker->id.cookie, RBD_LOCK_COOKIE_PREFIX " %llu", &cookie); for (i = 0; i < num_watchers; i++) { @@ -3985,8 +3987,12 @@ static int rbd_try_lock(struct rbd_device *rbd_dev) locker = refreshed_locker = NULL; ret = rbd_lock(rbd_dev); - if (ret != -EBUSY) + if (!ret) + goto out; + if (ret != -EBUSY) { + rbd_warn(rbd_dev, "failed to lock header: %d", ret); goto out; + } /* determine if the current lock holder is still alive */ locker = get_lock_owner_info(rbd_dev); @@ -4089,11 +4095,8 @@ static int rbd_try_acquire_lock(struct rbd_device *rbd_dev) ret = rbd_try_lock(rbd_dev); if (ret < 0) { - rbd_warn(rbd_dev, "failed to lock header: %d", ret); - if (ret == -EBLOCKLISTED) - goto out; - - ret = 1; /* request lock anyway */ + rbd_warn(rbd_dev, "failed to acquire lock: %d", ret); + goto out; } if (ret > 0) { up_write(&rbd_dev->lock_rwsem); @@ -6627,12 +6630,11 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev) cancel_delayed_work_sync(&rbd_dev->lock_dwork); if (!ret) ret = -ETIMEDOUT; - } - if (ret) { - rbd_warn(rbd_dev, "failed to acquire exclusive lock: %ld", ret); - return ret; + rbd_warn(rbd_dev, "failed to acquire lock: %ld", ret); } + if (ret) + return ret; /* * The lock may have been released by now, unless automatic lock -- cgit v1.2.3 From e6e2843230799230fc5deb8279728a7218b0d63c Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 1 Aug 2023 19:14:24 +0200 Subject: libceph: fix potential hang in ceph_osdc_notify() If the cluster becomes unavailable, ceph_osdc_notify() may hang even with osd_request_timeout option set because linger_notify_finish_wait() waits for MWatchNotify NOTIFY_COMPLETE message with no associated OSD request in flight -- it's completely asynchronous. Introduce an additional timeout, derived from the specified notify timeout. While at it, switch both waits to killable which is more correct. Cc: stable@vger.kernel.org Signed-off-by: Ilya Dryomov Reviewed-by: Dongsheng Yang Reviewed-by: Xiubo Li --- net/ceph/osd_client.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 11c04e7d928e..658a6f2320cf 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -3334,17 +3334,24 @@ static int linger_reg_commit_wait(struct ceph_osd_linger_request *lreq) int ret; dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id); - ret = wait_for_completion_interruptible(&lreq->reg_commit_wait); + ret = wait_for_completion_killable(&lreq->reg_commit_wait); return ret ?: lreq->reg_commit_error; } -static int linger_notify_finish_wait(struct ceph_osd_linger_request *lreq) +static int linger_notify_finish_wait(struct ceph_osd_linger_request *lreq, + unsigned long timeout) { - int ret; + long left; dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id); - ret = wait_for_completion_interruptible(&lreq->notify_finish_wait); - return ret ?: lreq->notify_finish_error; + left = wait_for_completion_killable_timeout(&lreq->notify_finish_wait, + ceph_timeout_jiffies(timeout)); + if (left <= 0) + left = left ?: -ETIMEDOUT; + else + left = lreq->notify_finish_error; /* completed */ + + return left; } /* @@ -4896,7 +4903,8 @@ int ceph_osdc_notify(struct ceph_osd_client *osdc, linger_submit(lreq); ret = linger_reg_commit_wait(lreq); if (!ret) - ret = linger_notify_finish_wait(lreq); + ret = linger_notify_finish_wait(lreq, + msecs_to_jiffies(2 * timeout * MSEC_PER_SEC)); else dout("lreq %p failed to initiate notify %d\n", lreq, ret); -- cgit v1.2.3 From 0a8589055936d8feb56477123a8373ac634018fa Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 24 Jul 2023 13:23:14 +0900 Subject: ata,scsi: do not issue START STOP UNIT on resume During system resume, ata_port_pm_resume() triggers ata EH to 1) Resume the controller 2) Reset and rescan the ports 3) Revalidate devices This EH execution is started asynchronously from ata_port_pm_resume(), which means that when sd_resume() is executed, none or only part of the above processing may have been executed. However, sd_resume() issues a START STOP UNIT to wake up the drive from sleep mode. This command is translated to ATA with ata_scsi_start_stop_xlat() and issued to the device. However, depending on the state of execution of the EH process and revalidation triggerred by ata_port_pm_resume(), two things may happen: 1) The START STOP UNIT fails if it is received before the controller has been reenabled at the beginning of the EH execution. This is visible with error messages like: ata10.00: device reported invalid CHS sector 0 sd 9:0:0:0: [sdc] Start/Stop Unit failed: Result: hostbyte=DID_OK driverbyte=DRIVER_OK sd 9:0:0:0: [sdc] Sense Key : Illegal Request [current] sd 9:0:0:0: [sdc] Add. Sense: Unaligned write command sd 9:0:0:0: PM: dpm_run_callback(): scsi_bus_resume+0x0/0x90 returns -5 sd 9:0:0:0: PM: failed to resume async: error -5 2) The START STOP UNIT command is received while the EH process is on-going, which mean that it is stopped and must wait for its completion, at which point the command is rather useless as the drive is already fully spun up already. This case results also in a significant delay in sd_resume() which is observable by users as the entire system resume completion is delayed. Given that ATA devices will be woken up by libata activity on resume, sd_resume() has no need to issue a START STOP UNIT command, which solves the above mentioned problems. Do not issue this command by introducing the new scsi_device flag no_start_on_resume and setting this flag to 1 in ata_scsi_dev_config(). sd_resume() is modified to issue a START STOP UNIT command only if this flag is not set. Reported-by: Paul Ausbeck Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215880 Fixes: a19a93e4c6a9 ("scsi: core: pm: Rely on the device driver core for async power management") Signed-off-by: Damien Le Moal Tested-by: Tanner Watkins Tested-by: Paul Ausbeck Reviewed-by: Hannes Reinecke Reviewed-by: Bart Van Assche --- drivers/ata/libata-scsi.c | 7 +++++++ drivers/scsi/sd.c | 9 ++++++--- include/scsi/scsi_device.h | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 370d18aca71e..c6ece32de8e3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1100,7 +1100,14 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) } } else { sdev->sector_size = ata_id_logical_sector_size(dev->id); + /* + * Stop the drive on suspend but do not issue START STOP UNIT + * on resume as this is not necessary and may fail: the device + * will be woken up by ata_port_pm_resume() with a port reset + * and device revalidation. + */ sdev->manage_start_stop = 1; + sdev->no_start_on_resume = 1; } /* diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 68b12afa0721..3c668cfb146d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3876,7 +3876,7 @@ static int sd_suspend_runtime(struct device *dev) static int sd_resume(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); - int ret; + int ret = 0; if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ return 0; @@ -3884,8 +3884,11 @@ static int sd_resume(struct device *dev) if (!sdkp->device->manage_start_stop) return 0; - sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); - ret = sd_start_stop_device(sdkp, 1); + if (!sdkp->device->no_start_on_resume) { + sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); + ret = sd_start_stop_device(sdkp, 1); + } + if (!ret) opal_unlock_from_suspend(sdkp->opal_dev); return ret; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 75b2235b99e2..b9230b6add04 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -194,6 +194,7 @@ struct scsi_device { unsigned no_start_on_add:1; /* do not issue start on add */ unsigned allow_restart:1; /* issue START_UNIT in error handler */ unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */ + unsigned no_start_on_resume:1; /* Do not issue START_STOP_UNIT on resume */ unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */ unsigned no_uld_attach:1; /* disable connecting to upper level drivers */ unsigned select_no_atn:1; -- cgit v1.2.3 From c71b7aa8619a0c9700132d0733e33999fb614339 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Wed, 2 Aug 2023 11:41:22 +0500 Subject: drm/panel: samsung-s6d7aa0: Add MODULE_DEVICE_TABLE The driver can be built as a module, however the lack of the MODULE_DEVICE_TABLE macro prevents it from being automatically probed from the DT in such case. Add the missed macro to make sure the module can load automatically. Fixes: 6810bb390282 ("drm/panel: Add Samsung S6D7AA0 panel controller driver") Signed-off-by: Nikita Travkin Acked-by: Artur Weber Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230802-gt5-panel-dtable-v1-1-c0a765c175e2@trvn.ru --- drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c index 102e1fc7ee38..be4ec5bb5223 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c @@ -569,6 +569,7 @@ static const struct of_device_id s6d7aa0_of_match[] = { }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, s6d7aa0_of_match); static struct mipi_dsi_driver s6d7aa0_driver = { .probe = s6d7aa0_probe, -- cgit v1.2.3 From 9bc3047374d5bec163e83e743709e23753376f0c Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 31 Jul 2023 18:42:36 +0200 Subject: net: tun_chr_open(): set sk_uid from current_fsuid() Commit a096ccca6e50 initializes the "sk_uid" field in the protocol socket (struct sock) from the "/dev/net/tun" device node's owner UID. Per original commit 86741ec25462 ("net: core: Add a UID field to struct sock.", 2016-11-04), that's wrong: the idea is to cache the UID of the userspace process that creates the socket. Commit 86741ec25462 mentions socket() and accept(); with "tun", the action that creates the socket is open("/dev/net/tun"). Therefore the device node's owner UID is irrelevant. In most cases, "/dev/net/tun" will be owned by root, so in practice, commit a096ccca6e50 has no observable effect: - before, "sk_uid" would be zero, due to undefined behavior (CVE-2023-1076), - after, "sk_uid" would be zero, due to "/dev/net/tun" being owned by root. What matters is the (fs)UID of the process performing the open(), so cache that in "sk_uid". Cc: Eric Dumazet Cc: Lorenzo Colitti Cc: Paolo Abeni Cc: Pietro Borrello Cc: netdev@vger.kernel.org Cc: stable@vger.kernel.org Fixes: a096ccca6e50 ("tun: tun_chr_open(): correctly initialize socket uid") Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2173435 Signed-off-by: Laszlo Ersek Signed-off-by: David S. Miller --- drivers/net/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d75456adc62a..25f0191df00b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -3469,7 +3469,7 @@ static int tun_chr_open(struct inode *inode, struct file * file) tfile->socket.file = file; tfile->socket.ops = &tun_socket_ops; - sock_init_data_uid(&tfile->socket, &tfile->sk, inode->i_uid); + sock_init_data_uid(&tfile->socket, &tfile->sk, current_fsuid()); tfile->sk.sk_write_space = tun_sock_write_space; tfile->sk.sk_sndbuf = INT_MAX; -- cgit v1.2.3 From 5c9241f3ceab3257abe2923a59950db0dc8bb737 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 31 Jul 2023 18:42:37 +0200 Subject: net: tap_open(): set sk_uid from current_fsuid() Commit 66b2c338adce initializes the "sk_uid" field in the protocol socket (struct sock) from the "/dev/tapX" device node's owner UID. Per original commit 86741ec25462 ("net: core: Add a UID field to struct sock.", 2016-11-04), that's wrong: the idea is to cache the UID of the userspace process that creates the socket. Commit 86741ec25462 mentions socket() and accept(); with "tap", the action that creates the socket is open("/dev/tapX"). Therefore the device node's owner UID is irrelevant. In most cases, "/dev/tapX" will be owned by root, so in practice, commit 66b2c338adce has no observable effect: - before, "sk_uid" would be zero, due to undefined behavior (CVE-2023-1076), - after, "sk_uid" would be zero, due to "/dev/tapX" being owned by root. What matters is the (fs)UID of the process performing the open(), so cache that in "sk_uid". Cc: Eric Dumazet Cc: Lorenzo Colitti Cc: Paolo Abeni Cc: Pietro Borrello Cc: netdev@vger.kernel.org Cc: stable@vger.kernel.org Fixes: 66b2c338adce ("tap: tap_open(): correctly initialize socket uid") Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2173435 Signed-off-by: Laszlo Ersek Signed-off-by: David S. Miller --- drivers/net/tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 9137fb8c1c42..49d1d6acf95e 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -534,7 +534,7 @@ static int tap_open(struct inode *inode, struct file *file) q->sock.state = SS_CONNECTED; q->sock.file = file; q->sock.ops = &tap_socket_ops; - sock_init_data_uid(&q->sock, &q->sk, inode->i_uid); + sock_init_data_uid(&q->sock, &q->sk, current_fsuid()); q->sk.sk_write_space = tap_sock_write_space; q->sk.sk_destruct = tap_sock_destruct; q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP; -- cgit v1.2.3 From 1cfef80d4c2b2c599189f36f36320b205d9447d9 Mon Sep 17 00:00:00 2001 From: Alexandra Winter Date: Tue, 1 Aug 2023 10:00:16 +0200 Subject: s390/qeth: Don't call dev_close/dev_open (DOWN/UP) dev_close() and dev_open() are issued to change the interface state to DOWN or UP (dev->flags IFF_UP). When the netdev is set DOWN it loses e.g its Ipv6 addresses and routes. We don't want this in cases of device recovery (triggered by hardware or software) or when the qeth device is set offline. Setting a qeth device offline or online and device recovery actions call netif_device_detach() and/or netif_device_attach(). That will reset or set the LOWER_UP indication i.e. change the dev->state Bit __LINK_STATE_PRESENT. That is enough to e.g. cause bond failovers, and still preserves the interface settings that are handled by the network stack. Don't call dev_open() nor dev_close() from the qeth device driver. Let the network stack handle this. Fixes: d4560150cb47 ("s390/qeth: call dev_close() during recovery") Signed-off-by: Alexandra Winter Reviewed-by: Wenjia Zhang Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 2 -- drivers/s390/net/qeth_l2_main.c | 9 ++++++--- drivers/s390/net/qeth_l3_main.c | 8 +++++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1d195429753d..613eab729704 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -716,7 +716,6 @@ struct qeth_card_info { u16 chid; u8 ids_valid:1; /* cssid,iid,chid */ u8 dev_addr_is_registered:1; - u8 open_when_online:1; u8 promisc_mode:1; u8 use_v1_blkt:1; u8 is_vm_nic:1; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1d5b207c2b9e..cd783290bde5 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5373,8 +5373,6 @@ int qeth_set_offline(struct qeth_card *card, const struct qeth_discipline *disc, qeth_clear_ipacmd_list(card); rtnl_lock(); - card->info.open_when_online = card->dev->flags & IFF_UP; - dev_close(card->dev); netif_device_detach(card->dev); netif_carrier_off(card->dev); rtnl_unlock(); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 9f13ed170a43..75910c0bcc2b 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -2388,9 +2388,12 @@ static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok) qeth_enable_hw_features(dev); qeth_l2_enable_brport_features(card); - if (card->info.open_when_online) { - card->info.open_when_online = 0; - dev_open(dev, NULL); + if (netif_running(dev)) { + local_bh_disable(); + napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); + qeth_l2_set_rx_mode(dev); } rtnl_unlock(); } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index af4e60d2917e..b92a32b4b114 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2018,9 +2018,11 @@ static int qeth_l3_set_online(struct qeth_card *card, bool carrier_ok) netif_device_attach(dev); qeth_enable_hw_features(dev); - if (card->info.open_when_online) { - card->info.open_when_online = 0; - dev_open(dev, NULL); + if (netif_running(dev)) { + local_bh_disable(); + napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } rtnl_unlock(); } -- cgit v1.2.3 From 30e0191b16e8a58e4620fa3e2839ddc7b9d4281c Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Tue, 1 Aug 2023 14:43:18 +0800 Subject: ip6mr: Fix skb_under_panic in ip6mr_cache_report() skbuff: skb_under_panic: text:ffffffff88771f69 len:56 put:-4 head:ffff88805f86a800 data:ffff887f5f86a850 tail:0x88 end:0x2c0 dev:pim6reg ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:192! invalid opcode: 0000 [#1] PREEMPT SMP KASAN CPU: 2 PID: 22968 Comm: kworker/2:11 Not tainted 6.5.0-rc3-00044-g0a8db05b571a #236 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Workqueue: ipv6_addrconf addrconf_dad_work RIP: 0010:skb_panic+0x152/0x1d0 Call Trace: skb_push+0xc4/0xe0 ip6mr_cache_report+0xd69/0x19b0 reg_vif_xmit+0x406/0x690 dev_hard_start_xmit+0x17e/0x6e0 __dev_queue_xmit+0x2d6a/0x3d20 vlan_dev_hard_start_xmit+0x3ab/0x5c0 dev_hard_start_xmit+0x17e/0x6e0 __dev_queue_xmit+0x2d6a/0x3d20 neigh_connected_output+0x3ed/0x570 ip6_finish_output2+0x5b5/0x1950 ip6_finish_output+0x693/0x11c0 ip6_output+0x24b/0x880 NF_HOOK.constprop.0+0xfd/0x530 ndisc_send_skb+0x9db/0x1400 ndisc_send_rs+0x12a/0x6c0 addrconf_dad_completed+0x3c9/0xea0 addrconf_dad_work+0x849/0x1420 process_one_work+0xa22/0x16e0 worker_thread+0x679/0x10c0 ret_from_fork+0x28/0x60 ret_from_fork_asm+0x11/0x20 When setup a vlan device on dev pim6reg, DAD ns packet may sent on reg_vif_xmit(). reg_vif_xmit() ip6mr_cache_report() skb_push(skb, -skb_network_offset(pkt));//skb_network_offset(pkt) is 4 And skb_push declared as: void *skb_push(struct sk_buff *skb, unsigned int len); skb->data -= len; //0xffff88805f86a84c - 0xfffffffc = 0xffff887f5f86a850 skb->data is set to 0xffff887f5f86a850, which is invalid mem addr, lead to skb_push() fails. Fixes: 14fb64e1f449 ("[IPV6] MROUTE: Support PIM-SM (SSM).") Signed-off-by: Yue Haibing Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index cc3d5ad17257..67a3b8f6e72b 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1073,7 +1073,7 @@ static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt, And all this only to mangle msg->im6_msgtype and to set msg->im6_mbz to "mbz" :-) */ - skb_push(skb, -skb_network_offset(pkt)); + __skb_pull(skb, skb_network_offset(pkt)); skb_push(skb, sizeof(*msg)); skb_reset_transport_header(skb); -- cgit v1.2.3 From 0756384fb1bd38adb2ebcfd1307422f433a1d772 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 31 Jul 2023 16:02:08 -0400 Subject: vxlan: Fix nexthop hash size The nexthop code expects a 31 bit hash, such as what is returned by fib_multipath_hash() and rt6_multipath_hash(). Passing the 32 bit hash returned by skb_get_hash() can lead to problems related to the fact that 'int hash' is a negative number when the MSB is set. In the case of hash threshold nexthop groups, nexthop_select_path_hthr() will disproportionately select the first nexthop group entry. In the case of resilient nexthop groups, nexthop_select_path_res() may do an out of bounds access in nh_buckets[], for example: hash = -912054133 num_nh_buckets = 2 bucket_index = 65535 which leads to the following panic: BUG: unable to handle page fault for address: ffffc900025910c8 PGD 100000067 P4D 100000067 PUD 10026b067 PMD 0 Oops: 0002 [#1] PREEMPT SMP KASAN NOPTI CPU: 4 PID: 856 Comm: kworker/4:3 Not tainted 6.5.0-rc2+ #34 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 Workqueue: ipv6_addrconf addrconf_dad_work RIP: 0010:nexthop_select_path+0x197/0xbf0 Code: c1 e4 05 be 08 00 00 00 4c 8b 35 a4 14 7e 01 4e 8d 6c 25 00 4a 8d 7c 25 08 48 01 dd e8 c2 25 15 ff 49 8d 7d 08 e8 39 13 15 ff <4d> 89 75 08 48 89 ef e8 7d 12 15 ff 48 8b 5d 00 e8 14 55 2f 00 85 RSP: 0018:ffff88810c36f260 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 00000000002000c0 RCX: ffffffffaf02dd77 RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffffc900025910c8 RBP: ffffc900025910c0 R08: 0000000000000001 R09: fffff520004b2219 R10: ffffc900025910cf R11: 31392d2068736168 R12: 00000000002000c0 R13: ffffc900025910c0 R14: 00000000fffef608 R15: ffff88811840e900 FS: 0000000000000000(0000) GS:ffff8881f7000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffc900025910c8 CR3: 0000000129d00000 CR4: 0000000000750ee0 PKRU: 55555554 Call Trace: ? __die+0x23/0x70 ? page_fault_oops+0x1ee/0x5c0 ? __pfx_is_prefetch.constprop.0+0x10/0x10 ? __pfx_page_fault_oops+0x10/0x10 ? search_bpf_extables+0xfe/0x1c0 ? fixup_exception+0x3b/0x470 ? exc_page_fault+0xf6/0x110 ? asm_exc_page_fault+0x26/0x30 ? nexthop_select_path+0x197/0xbf0 ? nexthop_select_path+0x197/0xbf0 ? lock_is_held_type+0xe7/0x140 vxlan_xmit+0x5b2/0x2340 ? __lock_acquire+0x92b/0x3370 ? __pfx_vxlan_xmit+0x10/0x10 ? __pfx___lock_acquire+0x10/0x10 ? __pfx_register_lock_class+0x10/0x10 ? skb_network_protocol+0xce/0x2d0 ? dev_hard_start_xmit+0xca/0x350 ? __pfx_vxlan_xmit+0x10/0x10 dev_hard_start_xmit+0xca/0x350 __dev_queue_xmit+0x513/0x1e20 ? __pfx___dev_queue_xmit+0x10/0x10 ? __pfx_lock_release+0x10/0x10 ? mark_held_locks+0x44/0x90 ? skb_push+0x4c/0x80 ? eth_header+0x81/0xe0 ? __pfx_eth_header+0x10/0x10 ? neigh_resolve_output+0x215/0x310 ? ip6_finish_output2+0x2ba/0xc90 ip6_finish_output2+0x2ba/0xc90 ? lock_release+0x236/0x3e0 ? ip6_mtu+0xbb/0x240 ? __pfx_ip6_finish_output2+0x10/0x10 ? find_held_lock+0x83/0xa0 ? lock_is_held_type+0xe7/0x140 ip6_finish_output+0x1ee/0x780 ip6_output+0x138/0x460 ? __pfx_ip6_output+0x10/0x10 ? __pfx___lock_acquire+0x10/0x10 ? __pfx_ip6_finish_output+0x10/0x10 NF_HOOK.constprop.0+0xc0/0x420 ? __pfx_NF_HOOK.constprop.0+0x10/0x10 ? ndisc_send_skb+0x2c0/0x960 ? __pfx_lock_release+0x10/0x10 ? __local_bh_enable_ip+0x93/0x110 ? lock_is_held_type+0xe7/0x140 ndisc_send_skb+0x4be/0x960 ? __pfx_ndisc_send_skb+0x10/0x10 ? mark_held_locks+0x65/0x90 ? find_held_lock+0x83/0xa0 ndisc_send_ns+0xb0/0x110 ? __pfx_ndisc_send_ns+0x10/0x10 addrconf_dad_work+0x631/0x8e0 ? lock_acquire+0x180/0x3f0 ? __pfx_addrconf_dad_work+0x10/0x10 ? mark_held_locks+0x24/0x90 process_one_work+0x582/0x9c0 ? __pfx_process_one_work+0x10/0x10 ? __pfx_do_raw_spin_lock+0x10/0x10 ? mark_held_locks+0x24/0x90 worker_thread+0x93/0x630 ? __kthread_parkme+0xdc/0x100 ? __pfx_worker_thread+0x10/0x10 kthread+0x1a5/0x1e0 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x34/0x60 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 RIP: 0000:0x0 Code: Unable to access opcode bytes at 0xffffffffffffffd6. RSP: 0000:0000000000000000 EFLAGS: 00000000 ORIG_RAX: 0000000000000000 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 Modules linked in: CR2: ffffc900025910c8 ---[ end trace 0000000000000000 ]--- RIP: 0010:nexthop_select_path+0x197/0xbf0 Code: c1 e4 05 be 08 00 00 00 4c 8b 35 a4 14 7e 01 4e 8d 6c 25 00 4a 8d 7c 25 08 48 01 dd e8 c2 25 15 ff 49 8d 7d 08 e8 39 13 15 ff <4d> 89 75 08 48 89 ef e8 7d 12 15 ff 48 8b 5d 00 e8 14 55 2f 00 85 RSP: 0018:ffff88810c36f260 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 00000000002000c0 RCX: ffffffffaf02dd77 RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffffc900025910c8 RBP: ffffc900025910c0 R08: 0000000000000001 R09: fffff520004b2219 R10: ffffc900025910cf R11: 31392d2068736168 R12: 00000000002000c0 R13: ffffc900025910c0 R14: 00000000fffef608 R15: ffff88811840e900 FS: 0000000000000000(0000) GS:ffff8881f7000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffffffffd6 CR3: 0000000129d00000 CR4: 0000000000750ee0 PKRU: 55555554 Kernel panic - not syncing: Fatal exception in interrupt Kernel Offset: 0x2ca00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]--- Fix this problem by ensuring the MSB of hash is 0 using a right shift - the same approach used in fib_multipath_hash() and rt6_multipath_hash(). Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries") Signed-off-by: Benjamin Poirier Reviewed-by: Ido Schimmel Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- include/net/vxlan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 1648240c9668..6a9f8a5f387c 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -556,12 +556,12 @@ static inline void vxlan_flag_attr_error(int attrtype, } static inline bool vxlan_fdb_nh_path_select(struct nexthop *nh, - int hash, + u32 hash, struct vxlan_rdst *rdst) { struct fib_nh_common *nhc; - nhc = nexthop_path_fdb_result(nh, hash); + nhc = nexthop_path_fdb_result(nh, hash >> 1); if (unlikely(!nhc)) return false; -- cgit v1.2.3 From 16e455a465fca91907af0108f3d013150386df30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 29 Jul 2023 16:05:00 +0200 Subject: wifi: brcmfmac: Fix field-spanning write in brcmf_scan_params_v2_to_v1() Using brcmfmac with 6.5-rc3 on a brcmfmac43241b4-sdio triggers a backtrace caused by the following field-spanning warning: memcpy: detected field-spanning write (size 120) of single field "¶ms_le->channel_list[0]" at drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:1072 (size 2) The driver still works after this warning. The warning was introduced by the new field-spanning write checks which were enabled recently. Fix this by replacing the channel_list[1] declaration at the end of the struct with a flexible array declaration. Most users of struct brcmf_scan_params_le calculate the size to alloc using the size of the non flex-array part of the struct + needed extra space, so they do not care about sizeof(struct brcmf_scan_params_le). brcmf_notify_escan_complete() however uses the struct on the stack, expecting there to be room for at least 1 entry in the channel-list to store the special -1 abort channel-id. To make this work use an anonymous union with a padding member added + the actual channel_list flexible array. Cc: Kees Cook Signed-off-by: Hans de Goede Reviewed-by: Kees Cook Reviewed-by: Franky Lin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230729140500.27892-1-hdegoede@redhat.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 792adaf880b4..bece26741d3a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -398,7 +398,12 @@ struct brcmf_scan_params_le { * fixed parameter portion is assumed, otherwise * ssid in the fixed portion is ignored */ - __le16 channel_list[1]; /* list of chanspecs */ + union { + __le16 padding; /* Reserve space for at least 1 entry for abort + * which uses an on stack brcmf_scan_params_le + */ + DECLARE_FLEX_ARRAY(__le16, channel_list); /* chanspecs */ + }; }; struct brcmf_scan_params_v2_le { -- cgit v1.2.3 From 51d765f79c8d8016df906afd05410f8bc14167ac Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:15 +0800 Subject: ASoC: fsl_micfil: Add new registers and new bit definition MICFIL IP is upgraded on i.MX93 platform. These new registers and new bit definition are added to complete the register list. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-2-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 6 ++++++ sound/soc/fsl/fsl_micfil.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index fe28b27e50d0..784188181542 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -825,6 +825,9 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: + case REG_MICFIL_FSYNC_CTRL: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: @@ -849,6 +852,7 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ + case REG_MICFIL_FSYNC_CTRL: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ @@ -873,6 +877,8 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: case REG_MICFIL_VAD0_NDATA: return true; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index 9237a1c4cb8f..b3c392ef5daf 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -24,6 +24,9 @@ #define REG_MICFIL_DC_CTRL 0x64 #define REG_MICFIL_OUT_CTRL 0x74 #define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_FSYNC_CTRL 0x80 +#define REG_MICFIL_VERID 0x84 +#define REG_MICFIL_PARAM 0x88 #define REG_MICFIL_VAD0_CTRL1 0x90 #define REG_MICFIL_VAD0_CTRL2 0x94 #define REG_MICFIL_VAD0_STAT 0x98 @@ -39,6 +42,8 @@ #define MICFIL_CTRL1_DBG BIT(28) #define MICFIL_CTRL1_SRES BIT(27) #define MICFIL_CTRL1_DBGE BIT(26) +#define MICFIL_CTRL1_DECFILS BIT(20) +#define MICFIL_CTRL1_FSYNCEN BIT(16) #define MICFIL_CTRL1_DISEL_DISABLE 0 #define MICFIL_CTRL1_DISEL_DMA 1 @@ -82,6 +87,29 @@ #define MICFIL_DC_CUTOFF_152Hz 2 #define MICFIL_DC_BYPASS 3 +/* MICFIL VERID Register -- REG_MICFIL_VERID */ +#define MICFIL_VERID_MAJOR_SHIFT 24 +#define MICFIL_VERID_MAJOR_MASK GENMASK(31, 24) +#define MICFIL_VERID_MINOR_SHIFT 16 +#define MICFIL_VERID_MINOR_MASK GENMASK(23, 16) +#define MICFIL_VERID_FEATURE_SHIFT 0 +#define MICFIL_VERID_FEATURE_MASK GENMASK(15, 0) + +/* MICFIL PARAM Register -- REG_MICFIL_PARAM */ +#define MICFIL_PARAM_NUM_HWVAD_SHIFT 24 +#define MICFIL_PARAM_NUM_HWVAD_MASK GENMASK(27, 24) +#define MICFIL_PARAM_HWVAD_ZCD BIT(19) +#define MICFIL_PARAM_HWVAD_ENERGY_MODE BIT(17) +#define MICFIL_PARAM_HWVAD BIT(16) +#define MICFIL_PARAM_DC_OUT_BYPASS BIT(11) +#define MICFIL_PARAM_DC_IN_BYPASS BIT(10) +#define MICFIL_PARAM_LOW_POWER BIT(9) +#define MICFIL_PARAM_FIL_OUT_WIDTH BIT(8) +#define MICFIL_PARAM_FIFO_PTRWID_SHIFT 4 +#define MICFIL_PARAM_FIFO_PTRWID_MASK GENMASK(7, 4) +#define MICFIL_PARAM_NPAIR_SHIFT 0 +#define MICFIL_PARAM_NPAIR_MASK GENMASK(3, 0) + /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ #define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24) #define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16) -- cgit v1.2.3 From 367365051b06e172c91172e3273eea72988ce8f6 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:16 +0800 Subject: ASoC: fsl_micfil: Add fsl_micfil_use_verid function fsl_micfil_use_verid() can help to parse the version info in VERID and PARAM registers. Since the two registers are added only on i.MX93 platform, a member flag called use_verid is introduced to soc data structure which indicates acquiring MICFIL version. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-3-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 76 ++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_micfil.h | 36 ++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 784188181542..ad8b39081739 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -56,6 +56,8 @@ struct fsl_micfil { int vad_init_mode; int vad_enabled; int vad_detected; + struct fsl_micfil_verid verid; + struct fsl_micfil_param param; }; struct fsl_micfil_soc_data { @@ -64,6 +66,7 @@ struct fsl_micfil_soc_data { unsigned int dataline; bool imx; bool use_edma; + bool use_verid; u64 formats; }; @@ -90,6 +93,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { .dataline = 0xf, .formats = SNDRV_PCM_FMTBIT_S32_LE, .use_edma = true, + .use_verid = true, }; static const struct of_device_id fsl_micfil_dt_ids[] = { @@ -356,6 +360,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), }; +static int fsl_micfil_use_verid(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (!micfil->soc->use_verid) + return 0; + + ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "VERID: 0x%016X\n", val); + + micfil->verid.version = val & + (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK); + micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT; + micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK; + + ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "PARAM: 0x%016X\n", val); + + micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >> + MICFIL_PARAM_NUM_HWVAD_SHIFT; + micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD; + micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE; + micfil->param.hwvad = val & MICFIL_PARAM_HWVAD; + micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS; + micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS; + micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER; + micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH; + micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >> + MICFIL_PARAM_FIFO_PTRWID_SHIFT; + micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >> + MICFIL_PARAM_NPAIR_SHIFT; + + return 0; +} + /* The SRES is a self-negated bit which provides the CPU with the * capability to initialize the PDM Interface module through the * slave-bus interface. This bit always reads as zero, and this @@ -1037,6 +1084,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid) return IRQ_HANDLED; } +static int fsl_micfil_runtime_suspend(struct device *dev); +static int fsl_micfil_runtime_resume(struct device *dev); + static int fsl_micfil_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1156,6 +1206,25 @@ static int fsl_micfil_probe(struct platform_device *pdev) platform_set_drvdata(pdev, micfil); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_micfil_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; + + /* Get micfil version */ + ret = fsl_micfil_use_verid(&pdev->dev); + if (ret < 0) + dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret); + + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0 && ret != -ENOSYS) + goto err_pm_get_sync; + regcache_cache_only(micfil->regmap, true); /* @@ -1180,6 +1249,9 @@ static int fsl_micfil_probe(struct platform_device *pdev) return ret; +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_micfil_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -1191,7 +1263,7 @@ static void fsl_micfil_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) +static int fsl_micfil_runtime_suspend(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); @@ -1203,7 +1275,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) +static int fsl_micfil_runtime_resume(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); int ret; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index b3c392ef5daf..231a52aff024 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -174,4 +174,40 @@ #define MICFIL_HWVAD_ENVELOPE_MODE 0 #define MICFIL_HWVAD_ENERGY_MODE 1 +/** + * struct fsl_micfil_verid - version id data + * @version: version number + * @feature: feature specification number + */ +struct fsl_micfil_verid { + u32 version; + u32 feature; +}; + +/** + * struct fsl_micfil_param - parameter data + * @hwvad_num: the number of HWVADs + * @hwvad_zcd: HWVAD zero-cross detector is active + * @hwvad_energy_mode: HWVAD energy mode is active + * @hwvad: HWVAD is active + * @dc_out_bypass: points out if the output DC remover is disabled + * @dc_in_bypass: points out if the input DC remover is disabled + * @low_power: low power decimation filter + * @fil_out_width: filter output width + * @fifo_ptrwid: FIFO pointer width + * @npair: number of microphone pairs + */ +struct fsl_micfil_param { + u32 hwvad_num; + bool hwvad_zcd; + bool hwvad_energy_mode; + bool hwvad; + bool dc_out_bypass; + bool dc_in_bypass; + bool low_power; + bool fil_out_width; + u32 fifo_ptrwid; + u32 npair; +}; + #endif /* _FSL_MICFIL_H */ -- cgit v1.2.3 From a38a4090e2c400c6c49c584cda6f28c73c08f5f1 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:17 +0800 Subject: ASoC: fsl_micfil: Use SET_SYSTEM_SLEEP_PM_OPS to simplify PM Use SET_SYSTEM_SLEEP_PM_OPS to simplify suspend and resume function. fsl_micfil_suspend() and fsl_micfil_resume() can be deleted. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-4-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index ad8b39081739..b07c27c780d9 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1297,26 +1297,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_suspend(struct device *dev) -{ - pm_runtime_force_suspend(dev); - - return 0; -} - -static int __maybe_unused fsl_micfil_resume(struct device *dev) -{ - pm_runtime_force_resume(dev); - - return 0; -} - static const struct dev_pm_ops fsl_micfil_pm_ops = { SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, fsl_micfil_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend, - fsl_micfil_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver fsl_micfil_driver = { -- cgit v1.2.3 From 86582e6189dd8f9f52c25d46c70fe5d111da6345 Mon Sep 17 00:00:00 2001 From: Benjamin Gray Date: Thu, 6 Jul 2023 11:08:16 +1000 Subject: powerpc/powermac: Use early_* IO variants in via_calibrate_decr() On a powermac platform, via the call path: start_kernel() time_init() ppc_md.calibrate_decr() (pmac_calibrate_decr) via_calibrate_decr() ioremap() and iounmap() are called. The unmap can enable interrupts unexpectedly (cond_resched() in vunmap_pmd_range()), which causes a warning later in the boot sequence in start_kernel(). Use the early_* variants of these IO functions to prevent this. The issue is pre-existing, but is surfaced by commit 721255b9826b ("genirq: Use a maple tree for interrupt descriptor management"). Signed-off-by: Benjamin Gray Reviewed-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://msgid.link/20230706010816.72682-1-bgray@linux.ibm.com --- arch/powerpc/platforms/powermac/time.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index 4c5790aff1b5..8633891b7aa5 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -26,8 +26,8 @@ #include #include +#include #include -#include #include #include #include @@ -182,7 +182,7 @@ static int __init via_calibrate_decr(void) return 0; } of_node_put(vias); - via = ioremap(rsrc.start, resource_size(&rsrc)); + via = early_ioremap(rsrc.start, resource_size(&rsrc)); if (via == NULL) { printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); return 0; @@ -207,7 +207,7 @@ static int __init via_calibrate_decr(void) ppc_tb_freq = (dstart - dend) * 100 / 6; - iounmap(via); + early_iounmap((void *)via, resource_size(&rsrc)); return 1; } -- cgit v1.2.3 From 79e8328e5acbe691bbde029a52c89d70dcbc22f3 Mon Sep 17 00:00:00 2001 From: "ndesaulniers@google.com" Date: Tue, 1 Aug 2023 15:22:17 -0700 Subject: word-at-a-time: use the same return type for has_zero regardless of endianness Compiling big-endian targets with Clang produces the diagnostic: fs/namei.c:2173:13: warning: use of bitwise '|' with boolean operands [-Wbitwise-instead-of-logical] } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants))); ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ || fs/namei.c:2173:13: note: cast one or both operands to int to silence this warning It appears that when has_zero was introduced, two definitions were produced with different signatures (in particular different return types). Looking at the usage in hash_name() in fs/namei.c, I suspect that has_zero() is meant to be invoked twice per while loop iteration; using logical-or would not update `bdata` when `a` did not have zeros. So I think it's preferred to always return an unsigned long rather than a bool than update the while loop in hash_name() to use a logical-or rather than bitwise-or. [ Also changed powerpc version to do the same - Linus ] Link: https://github.com/ClangBuiltLinux/linux/issues/1832 Link: https://lore.kernel.org/lkml/20230801-bitwise-v1-1-799bec468dc4@google.com/ Fixes: 36126f8f2ed8 ("word-at-a-time: make the interfaces truly generic") Debugged-by: Nathan Chancellor Signed-off-by: Nick Desaulniers Acked-by: Heiko Carstens Cc: Arnd Bergmann Signed-off-by: Linus Torvalds --- arch/powerpc/include/asm/word-at-a-time.h | 2 +- include/asm-generic/word-at-a-time.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h index 46c31fb8748d..30a12d208687 100644 --- a/arch/powerpc/include/asm/word-at-a-time.h +++ b/arch/powerpc/include/asm/word-at-a-time.h @@ -34,7 +34,7 @@ static inline long find_zero(unsigned long mask) return leading_zero_bits >> 3; } -static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) +static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) { unsigned long rhs = val | c->low_bits; *data = rhs; diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h index 20c93f08c993..95a1d214108a 100644 --- a/include/asm-generic/word-at-a-time.h +++ b/include/asm-generic/word-at-a-time.h @@ -38,7 +38,7 @@ static inline long find_zero(unsigned long mask) return (mask >> 8) ? byte : byte + 1; } -static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) +static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) { unsigned long rhs = val | c->low_bits; *data = rhs; -- cgit v1.2.3 From 11260c3d608b59231f4c228147a795ab21a10b33 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Wed, 2 Aug 2023 13:43:03 -0300 Subject: smb: client: fix dfs link mount against w2k8 Customer reported that they couldn't mount their DFS link that was seen by the client as a DFS interlink -- special form of DFS link where its single target may point to a different DFS namespace -- and it turned out that it was just a regular DFS link where its referral header flags missed the StorageServers bit thus making the client think it couldn't tree connect to target directly without requiring further referrals. When the DFS link referral header flags misses the StoraServers bit and its target doesn't respond to any referrals, then tree connect to it. Fixes: a1c0d00572fc ("cifs: share dfs connections and supers") Cc: stable@vger.kernel.org Signed-off-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- fs/smb/client/dfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c index df3fd3b720da..ee772c3d9f00 100644 --- a/fs/smb/client/dfs.c +++ b/fs/smb/client/dfs.c @@ -177,8 +177,12 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl); - if (rc) + if (rc) { + rc = cifs_mount_get_tcon(mnt_ctx); + if (!rc) + rc = cifs_is_path_remote(mnt_ctx); break; + } tit = dfs_cache_get_tgt_iterator(&tl); if (!tit) { -- cgit v1.2.3 From 8c82d2bf5944123d8e90d01bf27655497d9aa321 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Wed, 12 Jul 2023 12:35:14 -0700 Subject: selftests/riscv: fix potential build failure during the "emit_tests" step The riscv selftests (which were modeled after the arm64 selftests) are improperly declaring the "emit_tests" target to depend upon the "all" target. This approach, when combined with commit 9fc96c7c19df ("selftests: error out if kernel header files are not yet built"), has caused build failures [1] on arm64, and is likely to cause similar failures for riscv. To fix this, simply remove the unnecessary "all" dependency from the emit_tests target. The dependency is still effectively honored, because again, invocation is via "install", which also depends upon "all". An alternative approach would be to harden the emit_tests target so that it can depend upon "all", but that's a lot more complicated and hard to get right, and doesn't seem worth it, especially given that emit_tests should probably not be overridden at all. [1] https://lore.kernel.org/20230710-kselftest-fix-arm64-v1-1-48e872844f25@kernel.org Fixes: 9fc96c7c19df ("selftests: error out if kernel header files are not yet built") Signed-off-by: John Hubbard Tested-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230712193514.740033-1-jhubbard@nvidia.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- tools/testing/selftests/riscv/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile index 9dd629cc86aa..f4b3d5c9af5b 100644 --- a/tools/testing/selftests/riscv/Makefile +++ b/tools/testing/selftests/riscv/Makefile @@ -43,7 +43,7 @@ run_tests: all done # Avoid any output on non riscv on emit_tests -emit_tests: all +emit_tests: @for DIR in $(RISCV_SUBTARGETS); do \ BUILD_TARGET=$(OUTPUT)/$$DIR; \ $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@; \ -- cgit v1.2.3 From 25696067202f047e22c1562f1f56b0e2eb547d1a Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Thu, 13 Jul 2023 13:58:29 +0200 Subject: selftests: riscv: Fix compilation error with vstate_exec_nolibc.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following error happens: In file included from vstate_exec_nolibc.c:2: /usr/include/riscv64-linux-gnu/sys/prctl.h:42:12: error: conflicting types for ‘prctl’; h ave ‘int(int, ...)’ 42 | extern int prctl (int __option, ...) __THROW; | ^~~~~ In file included from ./../../../../include/nolibc/nolibc.h:99, from : ./../../../../include/nolibc/sys.h:892:5: note: previous definition of ‘prctl’ with type ‘int(int, long unsigned int, long unsigned int, long unsigned int, long unsigned int) ’ 892 | int prctl(int option, unsigned long arg2, unsigned long arg3, | ^~~~~ Fix this by not including , which is not needed here since prctl syscall is directly called using its number. Fixes: 7cf6198ce22d ("selftests: Test RISC-V Vector prctl interface") Signed-off-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230713115829.110421-1-alexghiti@rivosinc.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- tools/testing/selftests/riscv/vector/vstate_exec_nolibc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/testing/selftests/riscv/vector/vstate_exec_nolibc.c b/tools/testing/selftests/riscv/vector/vstate_exec_nolibc.c index 5cbc392944a6..2c0d2b1126c1 100644 --- a/tools/testing/selftests/riscv/vector/vstate_exec_nolibc.c +++ b/tools/testing/selftests/riscv/vector/vstate_exec_nolibc.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0-only -#include - #define THIS_PROGRAM "./vstate_exec_nolibc" int main(int argc, char **argv) -- cgit v1.2.3 From 568701fee36652a7660ed667a3980c945d8051e0 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 24 Jul 2023 15:33:46 +0530 Subject: RISC-V: ACPI: Fix acpi_os_ioremap to return iomem address acpi_os_ioremap() currently is a wrapper to memremap() on RISC-V. But the callers of acpi_os_ioremap() expect it to return __iomem address and hence sparse tool reports a new warning. Fix this issue by type casting to __iomem type. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307230357.egcTAefj-lkp@intel.com/ Fixes: a91a9ffbd3a5 ("RISC-V: Add support to build the ACPI core") Signed-off-by: Sunil V L Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230724100346.1302937-1-sunilvl@ventanamicro.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/acpi.h | 2 +- arch/riscv/kernel/acpi.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h index f71ce21ff684..d5604d2073bc 100644 --- a/arch/riscv/include/asm/acpi.h +++ b/arch/riscv/include/asm/acpi.h @@ -19,7 +19,7 @@ typedef u64 phys_cpuid_t; #define PHYS_CPUID_INVALID INVALID_HARTID /* ACPI table mapping after acpi_permanent_mmap is set */ -void *acpi_os_ioremap(acpi_physical_address phys, acpi_size size); +void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size); #define acpi_os_ioremap acpi_os_ioremap #define acpi_strict 1 /* No out-of-spec workarounds on RISC-V */ diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c index 5ee03ebab80e..56cb2c986c48 100644 --- a/arch/riscv/kernel/acpi.c +++ b/arch/riscv/kernel/acpi.c @@ -215,9 +215,9 @@ void __init __acpi_unmap_table(void __iomem *map, unsigned long size) early_iounmap(map, size); } -void *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) +void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) { - return memremap(phys, size, MEMREMAP_WB); + return (void __iomem *)memremap(phys, size, MEMREMAP_WB); } #ifdef CONFIG_PCI -- cgit v1.2.3 From fbe7d19d2b7fcbd38905ba9f691be8f245c6faa6 Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Mon, 24 Jul 2023 18:09:16 +0800 Subject: riscv: Export va_kernel_pa_offset in vmcoreinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since RISC-V Linux v6.4, the commit 3335068f8721 ("riscv: Use PUD/P4D/PGD pages for the linear mapping") changes phys_ram_base from the physical start of the kernel to the actual start of the DRAM. The Crash-utility's VTOP() still uses phys_ram_base and kernel_map.virt_addr to translate kernel virtual address, that failed the Crash with Linux v6.4 [1]. Export kernel_map.va_kernel_pa_offset in vmcoreinfo to help Crash translate the kernel virtual address correctly. Fixes: 3335068f8721 ("riscv: Use PUD/P4D/PGD pages for the linear mapping") Link: https://lore.kernel.org/linux-riscv/20230724040649.220279-1-suagrfillet@gmail.com/ [1] Signed-off-by: Song Shuai Reviewed-by: Xianting Tian  Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230724100917.309061-1-suagrfillet@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/crash_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/kernel/crash_core.c b/arch/riscv/kernel/crash_core.c index b351a3c01355..55f1d7856b54 100644 --- a/arch/riscv/kernel/crash_core.c +++ b/arch/riscv/kernel/crash_core.c @@ -18,4 +18,6 @@ void arch_crash_save_vmcoreinfo(void) vmcoreinfo_append_str("NUMBER(MODULES_END)=0x%lx\n", MODULES_END); #endif vmcoreinfo_append_str("NUMBER(KERNEL_LINK_ADDR)=0x%lx\n", KERNEL_LINK_ADDR); + vmcoreinfo_append_str("NUMBER(va_kernel_pa_offset)=0x%lx\n", + kernel_map.va_kernel_pa_offset); } -- cgit v1.2.3 From 640c503d7dbd7d34a62099c933f4db0ed77ccbec Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Mon, 24 Jul 2023 18:09:17 +0800 Subject: Documentation: kdump: Add va_kernel_pa_offset for RISCV64 RISC-V Linux exports "va_kernel_pa_offset" in vmcoreinfo to help Crash-utility translate the kernel virtual address correctly. Here adds the definition of "va_kernel_pa_offset". Fixes: 3335068f8721 ("riscv: Use PUD/P4D/PGD pages for the linear mapping") Link: https://lore.kernel.org/linux-riscv/20230724040649.220279-1-suagrfillet@gmail.com/ Signed-off-by: Song Shuai Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230724100917.309061-2-suagrfillet@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- Documentation/admin-guide/kdump/vmcoreinfo.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index c18d94fa6470..f8ebb63b6c5d 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -624,3 +624,9 @@ Used to get the correct ranges: * VMALLOC_START ~ VMALLOC_END : vmalloc() / ioremap() space. * VMEMMAP_START ~ VMEMMAP_END : vmemmap space, used for struct page array. * KERNEL_LINK_ADDR : start address of Kernel link and BPF + +va_kernel_pa_offset +------------------- + +Indicates the offset between the kernel virtual and physical mappings. +Used to translate virtual to physical addresses. -- cgit v1.2.3 From 9e2d0c336524706fb327e9b87477f5f3337ad7a6 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Fri, 23 Jun 2023 09:28:08 -0700 Subject: x86/hyperv: add noop functions to x86_init mpparse functions Hyper-V can run VMs at different privilege "levels" known as Virtual Trust Levels (VTL). Sometimes, it chooses to run two different VMs at different levels but they share some of their address space. In such setups VTL2 (higher level VM) has visibility of all of the VTL0 (level 0) memory space. When the CONFIG_X86_MPPARSE is enabled for VTL2, the VTL2 kernel performs a search within the low memory to locate MP tables. However, in systems where VTL0 manages the low memory and may contain valid tables, this scanning can result in incorrect MP table information being provided to the VTL2 kernel, mistakenly considering VTL0's MP table as its own Add noop functions to avoid MP parse scan by VTL2. Signed-off-by: Saurabh Sengar Acked-by: Dave Hansen Link: https://lore.kernel.org/r/1687537688-5397-1-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/hv_vtl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c index 85d38b9f3586..db5d2ea39fc0 100644 --- a/arch/x86/hyperv/hv_vtl.c +++ b/arch/x86/hyperv/hv_vtl.c @@ -25,6 +25,10 @@ void __init hv_vtl_init_platform(void) x86_init.irqs.pre_vector_init = x86_init_noop; x86_init.timers.timer_init = x86_init_noop; + /* Avoid searching for BIOS MP tables */ + x86_init.mpparse.find_smp_config = x86_init_noop; + x86_init.mpparse.get_smp_config = x86_init_uint_noop; + x86_platform.get_wallclock = get_rtc_noop; x86_platform.set_wallclock = set_rtc_noop; x86_platform.get_nmi_reason = hv_get_nmi_reason; -- cgit v1.2.3 From 6ad0f2f91ad14ba0a3c2990c054fd6fbe8100429 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 25 Jul 2023 22:21:08 +0800 Subject: Drivers: hv: vmbus: Remove unused extern declaration vmbus_ontimer() Since commit 30fbee49b071 ("Staging: hv: vmbus: Get rid of the unused function vmbus_ontimer()") this is not used anymore, so can remove it. Signed-off-by: YueHaibing Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20230725142108.27280-1-yuehaibing@huawei.com Signed-off-by: Wei Liu --- include/linux/hyperv.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index bfbc37ce223b..3ac3974b3c78 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1239,9 +1239,6 @@ extern int vmbus_recvpacket_raw(struct vmbus_channel *channel, u32 *buffer_actual_len, u64 *requestid); - -extern void vmbus_ontimer(unsigned long data); - /* Base driver object */ struct hv_driver { const char *name; -- cgit v1.2.3 From 618d28a535a0582617465d14e05f3881736a2962 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Mon, 31 Jul 2023 14:58:40 +0300 Subject: net/mlx5: fs_core: Make find_closest_ft more generic As find_closest_ft_recursive is called to find the closest FT, the first parameter of find_closest_ft can be changed from fs_prio to fs_node. Thus this function is extended to find the closest FT for the nodes of any type, not only prios, but also the sub namespaces. Signed-off-by: Jianbo Liu Signed-off-by: Leon Romanovsky Link: https://lore.kernel.org/r/d3962c2b443ec8dde7a740dc742a1f052d5e256c.1690803944.git.leonro@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 29 +++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index b4eb27e7f28b..221723694d44 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -905,18 +905,17 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root, return ft; } -/* If reverse is false then return the first flow table in next priority of - * prio in the tree, else return the last flow table in the previous priority - * of prio in the tree. +/* If reverse is false then return the first flow table next to the passed node + * in the tree, else return the last flow table before the node in the tree. */ -static struct mlx5_flow_table *find_closest_ft(struct fs_prio *prio, bool reverse) +static struct mlx5_flow_table *find_closest_ft(struct fs_node *node, bool reverse) { struct mlx5_flow_table *ft = NULL; struct fs_node *curr_node; struct fs_node *parent; - parent = prio->node.parent; - curr_node = &prio->node; + parent = node->parent; + curr_node = node; while (!ft && parent) { ft = find_closest_ft_recursive(parent, &curr_node->list, reverse); curr_node = parent; @@ -926,15 +925,15 @@ static struct mlx5_flow_table *find_closest_ft(struct fs_prio *prio, bool revers } /* Assuming all the tree is locked by mutex chain lock */ -static struct mlx5_flow_table *find_next_chained_ft(struct fs_prio *prio) +static struct mlx5_flow_table *find_next_chained_ft(struct fs_node *node) { - return find_closest_ft(prio, false); + return find_closest_ft(node, false); } /* Assuming all the tree is locked by mutex chain lock */ -static struct mlx5_flow_table *find_prev_chained_ft(struct fs_prio *prio) +static struct mlx5_flow_table *find_prev_chained_ft(struct fs_node *node) { - return find_closest_ft(prio, true); + return find_closest_ft(node, true); } static struct mlx5_flow_table *find_next_fwd_ft(struct mlx5_flow_table *ft, @@ -946,7 +945,7 @@ static struct mlx5_flow_table *find_next_fwd_ft(struct mlx5_flow_table *ft, next_ns = flow_act->action & MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_NS; fs_get_obj(prio, next_ns ? ft->ns->node.parent : ft->node.parent); - return find_next_chained_ft(prio); + return find_next_chained_ft(&prio->node); } static int connect_fts_in_prio(struct mlx5_core_dev *dev, @@ -977,7 +976,7 @@ static int connect_prev_fts(struct mlx5_core_dev *dev, { struct mlx5_flow_table *prev_ft; - prev_ft = find_prev_chained_ft(prio); + prev_ft = find_prev_chained_ft(&prio->node); if (prev_ft) { struct fs_prio *prev_prio; @@ -1123,7 +1122,7 @@ static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table if (err) return err; - next_ft = first_ft ? first_ft : find_next_chained_ft(prio); + next_ft = first_ft ? first_ft : find_next_chained_ft(&prio->node); err = connect_fwd_rules(dev, ft, next_ft); if (err) return err; @@ -1198,7 +1197,7 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa tree_init_node(&ft->node, del_hw_flow_table, del_sw_flow_table); next_ft = unmanaged ? ft_attr->next_ft : - find_next_chained_ft(fs_prio); + find_next_chained_ft(&fs_prio->node); ft->def_miss_action = ns->def_miss_action; ft->ns = ns; err = root->cmds->create_flow_table(root, ft, ft_attr, next_ft); @@ -2201,7 +2200,7 @@ static struct mlx5_flow_table *find_next_ft(struct mlx5_flow_table *ft) if (!list_is_last(&ft->node.list, &prio->node.children)) return list_next_entry(ft, node.list); - return find_next_chained_ft(prio); + return find_next_chained_ft(&prio->node); } static int update_root_ft_destroy(struct mlx5_flow_table *ft) -- cgit v1.2.3 From c635ca45a7a2023904a1f851e99319af7b87017d Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Mon, 31 Jul 2023 14:58:41 +0300 Subject: net/mlx5: fs_core: Skip the FTs in the same FS_TYPE_PRIO_CHAINS fs_prio In the cited commit, new type of FS_TYPE_PRIO_CHAINS fs_prio was added to support multiple parallel namespaces for multi-chains. And we skip all the flow tables under the fs_node of this type unconditionally, when searching for the next or previous flow table to connect for a new table. As this search function is also used for find new root table when the old one is being deleted, it will skip the entire FS_TYPE_PRIO_CHAINS fs_node next to the old root. However, new root table should be chosen from it if there is any table in it. Fix it by skipping only the flow tables in the same FS_TYPE_PRIO_CHAINS fs_node when finding the closest FT for a fs_node. Besides, complete the connecting from FTs of previous priority of prio because there should be multiple prevs after this fs_prio type is introduced. And also the next FT should be chosen from the first flow table next to the prio in the same FS_TYPE_PRIO_CHAINS fs_prio, if this prio is the first child. Fixes: 328edb499f99 ("net/mlx5: Split FDB fast path prio to multiple namespaces") Signed-off-by: Jianbo Liu Reviewed-by: Paul Blakey Signed-off-by: Leon Romanovsky Link: https://lore.kernel.org/r/7a95754df479e722038996c97c97b062b372591f.1690803944.git.leonro@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 80 ++++++++++++++++++++--- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 221723694d44..6b069fa411c5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -889,7 +889,7 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root, struct fs_node *iter = list_entry(start, struct fs_node, list); struct mlx5_flow_table *ft = NULL; - if (!root || root->type == FS_TYPE_PRIO_CHAINS) + if (!root) return NULL; list_for_each_advance_continue(iter, &root->children, reverse) { @@ -905,19 +905,42 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root, return ft; } +static struct fs_node *find_prio_chains_parent(struct fs_node *parent, + struct fs_node **child) +{ + struct fs_node *node = NULL; + + while (parent && parent->type != FS_TYPE_PRIO_CHAINS) { + node = parent; + parent = parent->parent; + } + + if (child) + *child = node; + + return parent; +} + /* If reverse is false then return the first flow table next to the passed node * in the tree, else return the last flow table before the node in the tree. + * If skip is true, skip the flow tables in the same prio_chains prio. */ -static struct mlx5_flow_table *find_closest_ft(struct fs_node *node, bool reverse) +static struct mlx5_flow_table *find_closest_ft(struct fs_node *node, bool reverse, + bool skip) { + struct fs_node *prio_chains_parent = NULL; struct mlx5_flow_table *ft = NULL; struct fs_node *curr_node; struct fs_node *parent; + if (skip) + prio_chains_parent = find_prio_chains_parent(node, NULL); parent = node->parent; curr_node = node; while (!ft && parent) { - ft = find_closest_ft_recursive(parent, &curr_node->list, reverse); + if (parent != prio_chains_parent) + ft = find_closest_ft_recursive(parent, &curr_node->list, + reverse); curr_node = parent; parent = curr_node->parent; } @@ -927,13 +950,13 @@ static struct mlx5_flow_table *find_closest_ft(struct fs_node *node, bool revers /* Assuming all the tree is locked by mutex chain lock */ static struct mlx5_flow_table *find_next_chained_ft(struct fs_node *node) { - return find_closest_ft(node, false); + return find_closest_ft(node, false, true); } /* Assuming all the tree is locked by mutex chain lock */ static struct mlx5_flow_table *find_prev_chained_ft(struct fs_node *node) { - return find_closest_ft(node, true); + return find_closest_ft(node, true, true); } static struct mlx5_flow_table *find_next_fwd_ft(struct mlx5_flow_table *ft, @@ -969,21 +992,55 @@ static int connect_fts_in_prio(struct mlx5_core_dev *dev, return 0; } +static struct mlx5_flow_table *find_closet_ft_prio_chains(struct fs_node *node, + struct fs_node *parent, + struct fs_node **child, + bool reverse) +{ + struct mlx5_flow_table *ft; + + ft = find_closest_ft(node, reverse, false); + + if (ft && parent == find_prio_chains_parent(&ft->node, child)) + return ft; + + return NULL; +} + /* Connect flow tables from previous priority of prio to ft */ static int connect_prev_fts(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft, struct fs_prio *prio) { + struct fs_node *prio_parent, *parent = NULL, *child, *node; struct mlx5_flow_table *prev_ft; + int err = 0; + + prio_parent = find_prio_chains_parent(&prio->node, &child); + + /* return directly if not under the first sub ns of prio_chains prio */ + if (prio_parent && !list_is_first(&child->list, &prio_parent->children)) + return 0; prev_ft = find_prev_chained_ft(&prio->node); - if (prev_ft) { + while (prev_ft) { struct fs_prio *prev_prio; fs_get_obj(prev_prio, prev_ft->node.parent); - return connect_fts_in_prio(dev, prev_prio, ft); + err = connect_fts_in_prio(dev, prev_prio, ft); + if (err) + break; + + if (!parent) { + parent = find_prio_chains_parent(&prev_prio->node, &child); + if (!parent) + break; + } + + node = child; + prev_ft = find_closet_ft_prio_chains(node, parent, &child, true); } - return 0; + return err; } static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio @@ -2194,12 +2251,19 @@ EXPORT_SYMBOL(mlx5_del_flow_rules); /* Assuming prio->node.children(flow tables) is sorted by level */ static struct mlx5_flow_table *find_next_ft(struct mlx5_flow_table *ft) { + struct fs_node *prio_parent, *child; struct fs_prio *prio; fs_get_obj(prio, ft->node.parent); if (!list_is_last(&ft->node.list, &prio->node.children)) return list_next_entry(ft, node.list); + + prio_parent = find_prio_chains_parent(&prio->node, &child); + + if (prio_parent && list_is_first(&child->list, &prio_parent->children)) + return find_closest_ft(&prio->node, false, false); + return find_next_chained_ft(&prio->node); } -- cgit v1.2.3 From 62da08331f1a2bef9d0148613133ce8e640a2f8d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 31 Jul 2023 14:58:42 +0300 Subject: net/mlx5e: Set proper IPsec source port in L4 selector Fix typo in setup_fte_upper_proto_match() where destination UDP port was used instead of source port. Fixes: a7385187a386 ("net/mlx5e: IPsec, support upper protocol selector field offload") Signed-off-by: Leon Romanovsky Link: https://lore.kernel.org/r/ffc024a4d192113103f392b0502688366ca88c1f.1690803944.git.leonro@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c index dbe87bf89c0d..832d36be4a17 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c @@ -808,9 +808,9 @@ static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upsp } if (upspec->sport) { - MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria, udp_dport, + MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria, udp_sport, upspec->sport_mask); - MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, udp_dport, upspec->sport); + MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, udp_sport, upspec->sport); } } -- cgit v1.2.3 From 0f71c9caf26726efea674646f566984e735cc3b9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 1 Aug 2023 16:48:53 +0100 Subject: udp: Fix __ip_append_data()'s handling of MSG_SPLICE_PAGES __ip_append_data() can get into an infinite loop when asked to splice into a partially-built UDP message that has more than the frag-limit data and up to the MTU limit. Something like: pipe(pfd); sfd = socket(AF_INET, SOCK_DGRAM, 0); connect(sfd, ...); send(sfd, buffer, 8161, MSG_CONFIRM|MSG_MORE); write(pfd[1], buffer, 8); splice(pfd[0], 0, sfd, 0, 0x4ffe0ul, 0); where the amount of data given to send() is dependent on the MTU size (in this instance an interface with an MTU of 8192). The problem is that the calculation of the amount to copy in __ip_append_data() goes negative in two places, and, in the second place, this gets subtracted from the length remaining, thereby increasing it. This happens when pagedlen > 0 (which happens for MSG_ZEROCOPY and MSG_SPLICE_PAGES), because the terms in: copy = datalen - transhdrlen - fraggap - pagedlen; then mostly cancel when pagedlen is substituted for, leaving just -fraggap. This causes: length -= copy + transhdrlen; to increase the length to more than the amount of data in msg->msg_iter, which causes skb_splice_from_iter() to be unable to fill the request and it returns less than 'copied' - which means that length never gets to 0 and we never exit the loop. Fix this by: (1) Insert a note about the dodgy calculation of 'copy'. (2) If MSG_SPLICE_PAGES, clear copy if it is negative from the above equation, so that 'offset' isn't regressed and 'length' isn't increased, which will mean that length and thus copy should match the amount left in the iterator. (3) When handling MSG_SPLICE_PAGES, give a warning and return -EIO if we're asked to splice more than is in the iterator. It might be better to not give the warning or even just give a 'short' write. [!] Note that this ought to also affect MSG_ZEROCOPY, but MSG_ZEROCOPY avoids the problem by simply assuming that everything asked for got copied, not just the amount that was in the iterator. This is a potential bug for the future. Fixes: 7ac7c987850c ("udp: Convert udp_sendpage() to use MSG_SPLICE_PAGES") Reported-by: syzbot+f527b971b4bdc8e79f9e@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000881d0606004541d1@google.com/ Signed-off-by: David Howells cc: David Ahern cc: Jens Axboe Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/1420063.1690904933@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- net/ipv4/ip_output.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 54d2d3a2d850..6ba1a0fafbaa 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1158,10 +1158,15 @@ alloc_new_skb: } copy = datalen - transhdrlen - fraggap - pagedlen; + /* [!] NOTE: copy will be negative if pagedlen>0 + * because then the equation reduces to -fraggap. + */ if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); goto error; + } else if (flags & MSG_SPLICE_PAGES) { + copy = 0; } offset += copy; @@ -1209,6 +1214,10 @@ alloc_new_skb: } else if (flags & MSG_SPLICE_PAGES) { struct msghdr *msg = from; + err = -EIO; + if (WARN_ON_ONCE(copy > msg->msg_iter.count)) + goto error; + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, sk->sk_allocation); if (err < 0) -- cgit v1.2.3 From 534fc31d09b706a16d83533e16b5dc855caf7576 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 3 Aug 2023 08:41:22 +0200 Subject: xen/netback: Fix buffer overrun triggered by unusual packet It is possible that a guest can send a packet that contains a head + 18 slots and yet has a len <= XEN_NETBACK_TX_COPY_LEN. This causes nr_slots to underflow in xenvif_get_requests() which then causes the subsequent loop's termination condition to be wrong, causing a buffer overrun of queue->tx_map_ops. Rework the code to account for the extra frag_overflow slots. This is CVE-2023-34319 / XSA-432. Fixes: ad7f402ae4f4 ("xen/netback: Ensure protocol headers don't fall in the non-linear area") Signed-off-by: Ross Lagerwall Reviewed-by: Paul Durrant Reviewed-by: Wei Liu Signed-off-by: Juergen Gross --- drivers/net/xen-netback/netback.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c8d20cddf658..88f760a7cbc3 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -396,7 +396,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue, struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops; struct xen_netif_tx_request *txp = first; - nr_slots = shinfo->nr_frags + 1; + nr_slots = shinfo->nr_frags + frag_overflow + 1; copy_count(skb) = 0; XENVIF_TX_CB(skb)->split_mask = 0; @@ -462,8 +462,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, } } - for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; - shinfo->nr_frags++, gop++) { + for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; + shinfo->nr_frags++, gop++, nr_slots--) { index = pending_index(queue->pending_cons++); pending_idx = queue->pending_ring[index]; xenvif_tx_create_map_op(queue, pending_idx, txp, @@ -476,12 +476,12 @@ static void xenvif_get_requests(struct xenvif_queue *queue, txp++; } - if (frag_overflow) { + if (nr_slots > 0) { shinfo = skb_shinfo(nskb); frags = shinfo->frags; - for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow; + for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; shinfo->nr_frags++, txp++, gop++) { index = pending_index(queue->pending_cons++); pending_idx = queue->pending_ring[index]; @@ -492,6 +492,11 @@ static void xenvif_get_requests(struct xenvif_queue *queue, } skb_shinfo(skb)->frag_list = nskb; + } else if (nskb) { + /* A frag_list skb was allocated but it is no longer needed + * because enough slots were converted to copy ops above. + */ + kfree_skb(nskb); } (*copy_ops) = cop - queue->tx_copy_ops; -- cgit v1.2.3 From e9d699af3f65d62cf195f0e7a039400093ab2af2 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 27 Jul 2023 18:01:10 +0800 Subject: drm/bridge: it6505: Check power state with it6505->powered in IRQ handler On system resume, the driver might call it6505_poweron directly if the runtime PM hasn't been enabled. In such case, pm_runtime_get_if_in_use will always return 0 because dev->power.runtime_status stays at RPM_SUSPENDED, and the IRQ will never be handled. Use it6505->powered from the driver struct fixes this because it always gets updated when it6505_poweron is called. Fixes: 5eb9a4314053 ("drm/bridge: it6505: Guard bridge power in IRQ handler") Signed-off-by: Pin-yen Lin Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230727100131.2338127-1-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 504d51c42f79..aadb396508c5 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2517,9 +2517,11 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) }; int int_status[3], i; - if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0) + if (it6505->enable_drv_hold || !it6505->powered) return IRQ_HANDLED; + pm_runtime_get_sync(dev); + int_status[0] = it6505_read(it6505, INT_STATUS_01); int_status[1] = it6505_read(it6505, INT_STATUS_02); int_status[2] = it6505_read(it6505, INT_STATUS_03); -- cgit v1.2.3 From 1cb9e2ef66d53b020842b18762e30d0eb4384de8 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Thu, 22 Jun 2023 17:20:17 +0200 Subject: drm/nouveau/gr: enable memory loads on helper invocation on all channels We have a lurking bug where Fragment Shader Helper Invocations can't load from memory. But this is actually required in OpenGL and is causing random hangs or failures in random shaders. It is unknown how widespread this issue is, but shaders hitting this can end up with infinite loops. We enable those only on all Kepler and newer GPUs where we use our own Firmware. Nvidia's firmware provides a way to set a kernelspace controlled list of mmio registers in the gr space from push buffers via MME macros. v2: drop code for gm200 and newer. Cc: Ben Skeggs Cc: David Airlie Cc: nouveau@lists.freedesktop.org Cc: stable@vger.kernel.org # 4.19+ Signed-off-by: Karol Herbst Reviewed-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20230622152017.2512101-1-kherbst@redhat.com --- drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 4 +++- drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c | 10 ++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 1 + 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index 00dbeda7e346..de161e7a04aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -117,6 +117,7 @@ void gk104_grctx_generate_r418800(struct gf100_gr *); extern const struct gf100_grctx_func gk110_grctx; void gk110_grctx_generate_r419eb0(struct gf100_gr *); +void gk110_grctx_generate_r419f78(struct gf100_gr *); extern const struct gf100_grctx_func gk110b_grctx; extern const struct gf100_grctx_func gk208_grctx; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 94233d0119df..52a234b1ef01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -906,7 +906,9 @@ static void gk104_grctx_generate_r419f78(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000); + + /* bit 3 set disables loads in fp helper invocations, we need it enabled */ + nvkm_mask(device, 0x419f78, 0x00000009, 0x00000000); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c index 4391458e1fb2..3acdd9eeb74a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c @@ -820,6 +820,15 @@ gk110_grctx_generate_r419eb0(struct gf100_gr *gr) nvkm_mask(device, 0x419eb0, 0x00001000, 0x00001000); } +void +gk110_grctx_generate_r419f78(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + /* bit 3 set disables loads in fp helper invocations, we need it enabled */ + nvkm_mask(device, 0x419f78, 0x00000008, 0x00000000); +} + const struct gf100_grctx_func gk110_grctx = { .main = gf100_grctx_generate_main, @@ -854,4 +863,5 @@ gk110_grctx = { .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .r418800 = gk104_grctx_generate_r418800, .r419eb0 = gk110_grctx_generate_r419eb0, + .r419f78 = gk110_grctx_generate_r419f78, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c index 7b9a34f9ec3c..5597e87624ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c @@ -103,4 +103,5 @@ gk110b_grctx = { .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .r418800 = gk104_grctx_generate_r418800, .r419eb0 = gk110_grctx_generate_r419eb0, + .r419f78 = gk110_grctx_generate_r419f78, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c index c78d07a8bb7d..612656496541 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c @@ -568,4 +568,5 @@ gk208_grctx = { .dist_skip_table = gf117_grctx_generate_dist_skip_table, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .r418800 = gk104_grctx_generate_r418800, + .r419f78 = gk110_grctx_generate_r419f78, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index beac66eb2a80..9906974ac3f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -988,4 +988,5 @@ gm107_grctx = { .r406500 = gm107_grctx_generate_r406500, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .r419e00 = gm107_grctx_generate_r419e00, + .r419f78 = gk110_grctx_generate_r419f78, }; -- cgit v1.2.3 From e4060dad253352382b20420d8ef98daab24dbc17 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 28 Jul 2023 18:58:57 -0400 Subject: drm/nouveau/nvkm/dp: Add workaround to fix DP 1.3+ DPCD issues Currently we use the drm_dp_dpcd_read_caps() helper in the DRM side of nouveau in order to read the DPCD of a DP connector, which makes sure we do the right thing and also check for extended DPCD caps. However, it turns out we're not currently doing this on the nvkm side since we don't have access to the drm_dp_aux structure there - which means that the DRM side of the driver and the NVKM side can end up with different DPCD capabilities for the same connector. Ideally in order to fix this, we just want to use the drm_dp_read_dpcd_caps() helper in nouveau. That's not currently possible though, and is going to depend on having a bunch of the DP code moved out of nvkm and into the DRM side of things as part of the GSP enablement work. Until then however, let's workaround this problem by porting a copy of drm_dp_read_dpcd_caps() into NVKM - which should fix this issue. Signed-off-by: Lyude Paul Reviewed-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/issues/211 Link: https://patchwork.freedesktop.org/patch/msgid/20230728225858.350581-1-lyude@redhat.com (cherry picked from commit cc4adf3a7323212f303bc9ff0f96346c44fcba06 in drm-misc-next) Cc: # 6.3+ Signed-off-by: Karol Herbst --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 48 ++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 40c8ea43c42f..b8ac66b4a2c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -26,6 +26,8 @@ #include "head.h" #include "ior.h" +#include + #include #include #include @@ -634,6 +636,50 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp) return outp->dp.rates != 0; } +/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps() + * converted to work inside nvkm. This is a temporary holdover until we start + * passing the drm_dp_aux device through NVKM + */ +static int +nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp) +{ + struct nvkm_i2c_aux *aux = outp->dp.aux; + u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; + int ret; + + ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE); + if (ret < 0) + return ret; + + /* + * Prior to DP1.3 the bit represented by + * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. + * If it is set DP_DPCD_REV at 0000h could be at a value less than + * the true capability of the panel. The only way to check is to + * then compare 0000h and 2200h. + */ + if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) + return 0; + + ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext)); + if (ret < 0) + return ret; + + if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { + OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n", + outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); + return 0; + } + + if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext))) + return 0; + + memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)); + + return 0; +} + void nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) { @@ -689,7 +735,7 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr)); } - if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, sizeof(outp->dp.dpcd))) { + if (!nvkm_dp_read_dpcd_caps(outp)) { const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; const u8 *rate; int rate_max; -- cgit v1.2.3 From 583893a66d731f5da010a3fa38a0460e05f0149b Mon Sep 17 00:00:00 2001 From: Sanjay R Mehta Date: Wed, 2 Aug 2023 06:11:49 -0500 Subject: thunderbolt: Fix Thunderbolt 3 display flickering issue on 2nd hot plug onwards Previously, on unplug events, the TMU mode was disabled first followed by the Time Synchronization Handshake, irrespective of whether the tb_switch_tmu_rate_write() API was successful or not. However, this caused a problem with Thunderbolt 3 (TBT3) devices, as the TSPacketInterval bits were always enabled by default, leading the host router to assume that the device router's TMU was already enabled and preventing it from initiating the Time Synchronization Handshake. As a result, TBT3 monitors experienced display flickering from the second hot plug onwards. To address this issue, we have modified the code to only disable the Time Synchronization Handshake during TMU disable if the tb_switch_tmu_rate_write() function is successful. This ensures that the TBT3 devices function correctly and eliminates the display flickering issue. Co-developed-by: Sanath S Signed-off-by: Sanath S Signed-off-by: Sanjay R Mehta Cc: stable@vger.kernel.org Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tmu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index 1269f417515b..0dfd1e083994 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -579,7 +579,9 @@ int tb_switch_tmu_disable(struct tb_switch *sw) * uni-directional mode and we don't want to change it's TMU * mode. */ - tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]); + ret = tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]); + if (ret) + return ret; tb_port_tmu_time_sync_disable(up); ret = tb_port_tmu_time_sync_disable(down); -- cgit v1.2.3 From 248c74bf42c16262f95f26523683334686a26263 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 3 Aug 2023 10:39:08 +0200 Subject: ASoC: mediatek: mt8186: Remove unused mutex. The mutex mutex_request_dram has no user. Remove mutex_request_dram. Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230803083908.9DxbPvOK@linutronix.de Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c index 539e3a023bc4..70ec101890d3 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -13,8 +13,6 @@ #include "mt8186-afe-clk.h" #include "mt8186-audsys-clk.h" -static DEFINE_MUTEX(mutex_request_dram); - static const char *aud_clks[CLK_NUM] = { [CLK_AFE] = "aud_afe_clk", [CLK_DAC] = "aud_dac_clk", -- cgit v1.2.3 From c2ff2b736c41cc63bb0aaec85cccfead9fbcfe92 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (IBM)" Date: Thu, 3 Aug 2023 09:24:04 +0300 Subject: parisc/mm: preallocate fixmap page tables at init Christoph Biedl reported early OOM on recent kernels: swapper: page allocation failure: order:0, mode:0x100(__GFP_ZERO), nodemask=(null) CPU: 0 PID: 0 Comm: swapper Not tainted 6.3.0-rc4+ #16 Hardware name: 9000/785/C3600 Backtrace: [<10408594>] show_stack+0x48/0x5c [<10e152d8>] dump_stack_lvl+0x48/0x64 [<10e15318>] dump_stack+0x24/0x34 [<105cf7f8>] warn_alloc+0x10c/0x1c8 [<105d068c>] __alloc_pages+0xbbc/0xcf8 [<105d0e4c>] __get_free_pages+0x28/0x78 [<105ad10c>] __pte_alloc_kernel+0x30/0x98 [<10406934>] set_fixmap+0xec/0xf4 [<10411ad4>] patch_map.constprop.0+0xa8/0xdc [<10411bb0>] __patch_text_multiple+0xa8/0x208 [<10411d78>] patch_text+0x30/0x48 [<1041246c>] arch_jump_label_transform+0x90/0xcc [<1056f734>] jump_label_update+0xd4/0x184 [<1056fc9c>] static_key_enable_cpuslocked+0xc0/0x110 [<1056fd08>] static_key_enable+0x1c/0x2c [<1011362c>] init_mem_debugging_and_hardening+0xdc/0xf8 [<1010141c>] start_kernel+0x5f0/0xa98 [<10105da8>] start_parisc+0xb8/0xe4 Mem-Info: active_anon:0 inactive_anon:0 isolated_anon:0 active_file:0 inactive_file:0 isolated_file:0 unevictable:0 dirty:0 writeback:0 slab_reclaimable:0 slab_unreclaimable:0 mapped:0 shmem:0 pagetables:0 sec_pagetables:0 bounce:0 kernel_misc_reclaimable:0 free:0 free_pcp:0 free_cma:0 Node 0 active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:0kB dirty:0kB writeback:0kB shmem:0kB +writeback_tmp:0kB kernel_stack:0kB pagetables:0kB sec_pagetables:0kB all_unreclaimable? no Normal free:0kB boost:0kB min:0kB low:0kB high:0kB reserved_highatomic:0KB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB +present:1048576kB managed:1039360kB mlocked:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB lowmem_reserve[]: 0 0 Normal: 0*4kB 0*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 0kB 0 total pagecache pages 0 pages in swap cache Free swap = 0kB Total swap = 0kB 262144 pages RAM 0 pages HighMem/MovableOnly 2304 pages reserved Backtrace: [<10411d78>] patch_text+0x30/0x48 [<1041246c>] arch_jump_label_transform+0x90/0xcc [<1056f734>] jump_label_update+0xd4/0x184 [<1056fc9c>] static_key_enable_cpuslocked+0xc0/0x110 [<1056fd08>] static_key_enable+0x1c/0x2c [<1011362c>] init_mem_debugging_and_hardening+0xdc/0xf8 [<1010141c>] start_kernel+0x5f0/0xa98 [<10105da8>] start_parisc+0xb8/0xe4 Kernel Fault: Code=15 (Data TLB miss fault) at addr 0f7fe3c0 CPU: 0 PID: 0 Comm: swapper Not tainted 6.3.0-rc4+ #16 Hardware name: 9000/785/C3600 This happens because patching static key code temporarily maps it via fixmap and if it happens before page allocator is initialized set_fixmap() cannot allocate memory using pte_alloc_kernel(). Make sure that fixmap page tables are preallocated early so that pte_offset_kernel() in set_fixmap() never resorts to pte allocation. Signed-off-by: Mike Rapoport (IBM) Acked-by: Vlastimil Babka Signed-off-by: Helge Deller Tested-by: Christoph Biedl Tested-by: John David Anglin Cc: # v6.4+ --- arch/parisc/mm/fixmap.c | 3 --- arch/parisc/mm/init.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/arch/parisc/mm/fixmap.c b/arch/parisc/mm/fixmap.c index cc15d737fda6..ae3493dae9dc 100644 --- a/arch/parisc/mm/fixmap.c +++ b/arch/parisc/mm/fixmap.c @@ -19,9 +19,6 @@ void notrace set_fixmap(enum fixed_addresses idx, phys_addr_t phys) pmd_t *pmd = pmd_offset(pud, vaddr); pte_t *pte; - if (pmd_none(*pmd)) - pte = pte_alloc_kernel(pmd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); set_pte_at(&init_mm, vaddr, pte, __mk_pte(phys, PAGE_KERNEL_RWX)); flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE); diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 406c52fe23d5..389941c7f209 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -669,6 +669,39 @@ static void __init gateway_init(void) PAGE_SIZE, PAGE_GATEWAY, 1); } +static void __init fixmap_init(void) +{ + unsigned long addr = FIXMAP_START; + unsigned long end = FIXMAP_START + FIXMAP_SIZE; + pgd_t *pgd = pgd_offset_k(addr); + p4d_t *p4d = p4d_offset(pgd, addr); + pud_t *pud = pud_offset(p4d, addr); + pmd_t *pmd; + + BUILD_BUG_ON(FIXMAP_SIZE > PMD_SIZE); + +#if CONFIG_PGTABLE_LEVELS == 3 + if (pud_none(*pud)) { + pmd = memblock_alloc(PAGE_SIZE << PMD_TABLE_ORDER, + PAGE_SIZE << PMD_TABLE_ORDER); + if (!pmd) + panic("fixmap: pmd allocation failed.\n"); + pud_populate(NULL, pud, pmd); + } +#endif + + pmd = pmd_offset(pud, addr); + do { + pte_t *pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + if (!pte) + panic("fixmap: pte allocation failed.\n"); + + pmd_populate_kernel(&init_mm, pmd, pte); + + addr += PAGE_SIZE; + } while (addr < end); +} + static void __init parisc_bootmem_free(void) { unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0, }; @@ -683,6 +716,7 @@ void __init paging_init(void) setup_bootmem(); pagetable_init(); gateway_init(); + fixmap_init(); flush_cache_all_local(); /* start with known state */ flush_tlb_all_local(NULL); -- cgit v1.2.3 From ce9ff57d393db86a34ba3f817d7fb886b7c278dc Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Wed, 2 Aug 2023 18:33:21 +0200 Subject: parisc: pci-dma: remove unused and dead EISA code and comment Clearly, this code isn't needed, but it gives a false positive when grepping the complete source tree for coherent_dma_mask. Signed-off-by: Petr Tesarik Signed-off-by: Helge Deller --- arch/parisc/kernel/pci-dma.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index d818ece23b4a..3f6b507970eb 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -417,14 +417,6 @@ void *arch_dma_alloc(struct device *dev, size_t size, map_uncached_pages(vaddr, size, paddr); *dma_handle = (dma_addr_t) paddr; -#if 0 -/* This probably isn't needed to support EISA cards. -** ISA cards will certainly only support 24-bit DMA addressing. -** Not clear if we can, want, or need to support ISA. -*/ - if (!dev || *dev->coherent_dma_mask < 0xffffffff) - gfp |= GFP_DMA; -#endif return (void *)vaddr; } -- cgit v1.2.3 From 2e1b1d7063a35ab6cf9984f9d5bc29829e1e8788 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Jul 2023 17:09:14 +0200 Subject: parport: gsc: remove DMA leftover code This driver does not actually work with DMA mode, but still tries to call ISA DMA interface functions that are stubbed out on parisc, resulting in a W=1 build warning: drivers/parport/parport_gsc.c: In function 'parport_remove_chip': drivers/parport/parport_gsc.c:389:20: warning: suggest braces around empty body in an 'if' statement [-Wempty-body] 389 | free_dma(p->dma); Remove the corresponding code as a prerequisite for turning on -Wempty-body by default in all kernels. Signed-off-by: Arnd Bergmann Signed-off-by: Helge Deller --- drivers/parport/parport_gsc.c | 28 ++++------------------------ drivers/parport/parport_gsc.h | 7 ------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 0dcc497b0449..5e4475254bd0 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -226,9 +225,9 @@ static int parport_PS2_supported(struct parport *pb) /* --- Initialisation code -------------------------------- */ -struct parport *parport_gsc_probe_port(unsigned long base, +static struct parport *parport_gsc_probe_port(unsigned long base, unsigned long base_hi, int irq, - int dma, struct parisc_device *padev) + struct parisc_device *padev) { struct parport_gsc_private *priv; struct parport_operations *ops; @@ -250,12 +249,9 @@ struct parport *parport_gsc_probe_port(unsigned long base, } priv->ctr = 0xc; priv->ctr_writable = 0xff; - priv->dma_buf = NULL; - priv->dma_handle = 0; p->base = base; p->base_hi = base_hi; p->irq = irq; - p->dma = dma; p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; p->ops = ops; p->private_data = priv; @@ -286,17 +282,9 @@ struct parport *parport_gsc_probe_port(unsigned long base, if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; } - if (p->irq != PARPORT_IRQ_NONE) { + if (p->irq != PARPORT_IRQ_NONE) pr_cont(", irq %d", p->irq); - if (p->dma == PARPORT_DMA_AUTO) { - p->dma = PARPORT_DMA_NONE; - } - } - if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq - is mandatory (see above) */ - p->dma = PARPORT_DMA_NONE; - pr_cont(" ["); #define printmode(x) \ do { \ @@ -321,7 +309,6 @@ do { \ pr_warn("%s: irq %d in use, resorting to polled operation\n", p->name, p->irq); p->irq = PARPORT_IRQ_NONE; - p->dma = PARPORT_DMA_NONE; } } @@ -369,8 +356,7 @@ static int __init parport_init_chip(struct parisc_device *dev) pr_info("%s: enhanced parport-modes not supported\n", __func__); } - p = parport_gsc_probe_port(port, 0, dev->irq, - /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, dev); + p = parport_gsc_probe_port(port, 0, dev->irq, dev); if (p) parport_count++; dev_set_drvdata(&dev->dev, p); @@ -382,16 +368,10 @@ static void __exit parport_remove_chip(struct parisc_device *dev) { struct parport *p = dev_get_drvdata(&dev->dev); if (p) { - struct parport_gsc_private *priv = p->private_data; struct parport_operations *ops = p->ops; parport_remove_port(p); - if (p->dma != PARPORT_DMA_NONE) - free_dma(p->dma); if (p->irq != PARPORT_IRQ_NONE) free_irq(p->irq, p); - if (priv->dma_buf) - dma_free_coherent(&priv->dev->dev, PAGE_SIZE, - priv->dma_buf, priv->dma_handle); kfree (p->private_data); parport_put_port(p); kfree (ops); /* hope no-one cached it */ diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h index 9301217edf12..d447a568c257 100644 --- a/drivers/parport/parport_gsc.h +++ b/drivers/parport/parport_gsc.h @@ -63,8 +63,6 @@ struct parport_gsc_private { int writeIntrThreshold; /* buffer suitable for DMA, if DMA enabled */ - char *dma_buf; - dma_addr_t dma_handle; struct pci_dev *dev; }; @@ -199,9 +197,4 @@ extern void parport_gsc_inc_use_count(void); extern void parport_gsc_dec_use_count(void); -extern struct parport *parport_gsc_probe_port(unsigned long base, - unsigned long base_hi, - int irq, int dma, - struct parisc_device *padev); - #endif /* __DRIVERS_PARPORT_PARPORT_GSC_H */ -- cgit v1.2.3 From 99b2f159b6e76b84357eae6dc2a206871aa630d5 Mon Sep 17 00:00:00 2001 From: "hanyu001@208suo.com" Date: Thu, 20 Jul 2023 14:40:27 +0800 Subject: parisc: unaligned: Add required spaces after ',' Fix checkpatch warnings: unaligned.c:475: ERROR: space required after that ',' Signed-off-by: Yu Han Signed-off-by: Helge Deller --- arch/parisc/kernel/unaligned.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 033b9e50b44a..813062701922 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -337,7 +337,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) : "r19", "r20", "r21", "r22", "r1" ); #else { - unsigned long valh=(val>>32),vall=(val&0xffffffffl); + unsigned long valh = (val >> 32), vall = (val & 0xffffffffl); __asm__ __volatile__ ( " mtsp %4, %%sr1\n" " zdep %2, 29, 2, %%r19\n" @@ -473,7 +473,7 @@ void handle_unaligned(struct pt_regs *regs) case OPCODE_LDWA_I: case OPCODE_LDW_S: case OPCODE_LDWA_S: - ret = emulate_ldw(regs, R3(regs->iir),0); + ret = emulate_ldw(regs, R3(regs->iir), 0); break; case OPCODE_STH: @@ -482,7 +482,7 @@ void handle_unaligned(struct pt_regs *regs) case OPCODE_STW: case OPCODE_STWA: - ret = emulate_stw(regs, R2(regs->iir),0); + ret = emulate_stw(regs, R2(regs->iir), 0); break; #ifdef CONFIG_64BIT @@ -490,12 +490,12 @@ void handle_unaligned(struct pt_regs *regs) case OPCODE_LDDA_I: case OPCODE_LDD_S: case OPCODE_LDDA_S: - ret = emulate_ldd(regs, R3(regs->iir),0); + ret = emulate_ldd(regs, R3(regs->iir), 0); break; case OPCODE_STD: case OPCODE_STDA: - ret = emulate_std(regs, R2(regs->iir),0); + ret = emulate_std(regs, R2(regs->iir), 0); break; #endif @@ -503,24 +503,24 @@ void handle_unaligned(struct pt_regs *regs) case OPCODE_FLDWS: case OPCODE_FLDWXR: case OPCODE_FLDWSR: - ret = emulate_ldw(regs,FR3(regs->iir),1); + ret = emulate_ldw(regs, FR3(regs->iir), 1); break; case OPCODE_FLDDX: case OPCODE_FLDDS: - ret = emulate_ldd(regs,R3(regs->iir),1); + ret = emulate_ldd(regs, R3(regs->iir), 1); break; case OPCODE_FSTWX: case OPCODE_FSTWS: case OPCODE_FSTWXR: case OPCODE_FSTWSR: - ret = emulate_stw(regs,FR3(regs->iir),1); + ret = emulate_stw(regs, FR3(regs->iir), 1); break; case OPCODE_FSTDX: case OPCODE_FSTDS: - ret = emulate_std(regs,R3(regs->iir),1); + ret = emulate_std(regs, R3(regs->iir), 1); break; case OPCODE_LDCD_I: -- cgit v1.2.3 From 5a78d5db9c90c9dc84212f40a5f2687b7cafc8ec Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 1 Aug 2023 21:09:51 +0200 Subject: gpio: sim: mark the GPIO chip as a one that can sleep Simulated chips use a mutex for synchronization in driver callbacks so they must not be called from interrupt context. Set the can_sleep field of the GPIO chip to true to force users to only use threaded irqs. Fixes: cb8c474e79be ("gpio: sim: new testing module") Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpio-sim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 8b49b0abacd5..f1f6f1c32987 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -429,6 +429,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->set_config = gpio_sim_set_config; gc->to_irq = gpio_sim_to_irq; gc->free = gpio_sim_free; + gc->can_sleep = true; ret = devm_gpiochip_add_data(dev, gc, chip); if (ret) -- cgit v1.2.3 From c9bb40b7f786662e33d71afe236442b0b61f0446 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Aug 2023 00:46:39 +0100 Subject: arm64/fpsimd: Clear SME state in the target task when setting the VL When setting SME vector lengths we clear TIF_SME to reenable SME traps, doing a reallocation of the backing storage on next use. We do this using clear_thread_flag() which operates on the current thread, meaning that when setting the vector length via ptrace we may both not force traps for the target task and force a spurious flush of any SME state that the tracing task may have. Clear the flag in the target task. Fixes: e12310a0d30f ("arm64/sme: Implement ptrace support for streaming mode SVE registers") Reported-by: David Spickett Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230803-arm64-fix-ptrace-tif-sme-v1-1-88312fd6fbfd@kernel.org Signed-off-by: Catalin Marinas --- arch/arm64/kernel/fpsimd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 520b681a07bb..a61a1fd6492d 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -909,7 +909,7 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type, */ task->thread.svcr &= ~(SVCR_SM_MASK | SVCR_ZA_MASK); - clear_thread_flag(TIF_SME); + clear_tsk_thread_flag(task, TIF_SME); free_sme = true; } } -- cgit v1.2.3 From 89a65c3f170e5c3b05a626046c68354e2afd7912 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Aug 2023 01:19:06 +0100 Subject: arm64/ptrace: Flush FP state when setting ZT0 When setting ZT0 via ptrace we do not currently force a reload of the floating point register state from memory, do that to ensure that the newly set value gets loaded into the registers on next task execution. The function was templated off the function for FPSIMD which due to our providing the option of embedding a FPSIMD regset within the SVE regset does not directly include the flush. Fixes: f90b529bcbe5 ("arm64/sme: Implement ZT0 ptrace support") Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230803-arm64-fix-ptrace-zt0-flush-v1-1-72e854eaf96e@kernel.org Signed-off-by: Catalin Marinas --- arch/arm64/kernel/ptrace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index d7f4f0d1ae12..740e81e9db04 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -1180,6 +1180,8 @@ static int zt_set(struct task_struct *target, if (ret == 0) target->thread.svcr |= SVCR_ZA_MASK; + fpsimd_flush_task_state(target); + return ret; } -- cgit v1.2.3 From 421dabcad1c69e02a41c0d601aefbc29ee3f5368 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 3 Aug 2023 16:33:48 +0200 Subject: drm/nouveau: remove unused tu102_gr_load() function tu102_gr_load() is completely unused and can be removed to address this warning: drivers/gpu/drm/nouveau/dispnv50/disp.c:2517:1: error: no previous prototype for 'nv50_display_create' Another patch was sent in the meantime to mark the function static but that would just cause a different warning about an unused function. Fixes: 1cd97b5490c8 ("drm/nouveau/gr/tu102-: use sw_veid_bundle_init from firmware") Link: https://lore.kernel.org/all/CACO55tuaNOYphHyB9+ygi9AnXVuF49etsW7x2X5K5iEtFNAAyw@mail.gmail.com/ Link: https://lore.kernel.org/all/20230417210310.2443152-1-arnd@kernel.org/ Signed-off-by: Arnd Bergmann Reviewed-by: Karol Herbst Signed-off-by: Karol Herbst Link: https://patchwork.freedesktop.org/patch/msgid/20230803143358.13563-1-arnd@kernel.org --- drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c index 3b6c8100a242..a7775aa18541 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c @@ -206,19 +206,6 @@ tu102_gr_av_to_init_veid(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) return gk20a_gr_av_to_init_(blob, 64, 0x00100000, ppack); } -int -tu102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif) -{ - int ret; - - ret = gm200_gr_load(gr, ver, fwif); - if (ret) - return ret; - - return gk20a_gr_load_net(gr, "gr/", "sw_veid_bundle_init", ver, tu102_gr_av_to_init_veid, - &gr->bundle_veid); -} - static const struct gf100_gr_fwif tu102_gr_fwif[] = { { 0, gm200_gr_load, &tu102_gr, &gp108_gr_fecs_acr, &gp108_gr_gpccs_acr }, -- cgit v1.2.3 From 9f0d4d47c7915ce21bde4a4974a7a6307e244a6d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 3 Aug 2023 17:23:12 +0100 Subject: ASoC: soc-acpi: Add missing kernel doc The UID field in snd_soc_acpi_link_adr is not documented, add kernel doc for it. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230803162312.117771-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 630bf7367fe6..6d31d535e8f6 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -151,6 +151,7 @@ struct snd_soc_acpi_link_adr { * all firmware/topology related fields. * * @id: ACPI ID (usually the codec's) used to find a matching machine driver. + * @uid: ACPI Unique ID, can be used to disambiguate matches. * @comp_ids: list of compatible audio codecs using the same machine driver, * firmware and topology * @link_mask: describes required board layout, e.g. for SoundWire. -- cgit v1.2.3 From b755c25fbcd568821a3bb0e0d5c2daa5fcb00bba Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 2 Aug 2023 11:23:56 +0200 Subject: prestera: fix fallback to previous version on same major version When both supported and previous version have the same major version, and the firmwares are missing, the driver ends in a loop requesting the same (previous) version over and over again: [ 76.327413] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.1.img firmware, fall-back to previous 4.0 version [ 76.339802] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.352162] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.364502] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.376848] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.389183] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.401522] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.413860] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version [ 76.426199] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version ... Fix this by inverting the check to that we aren't yet at the previous version, and also check the minor version. This also catches the case where both versions are the same, as it was after commit bb5dbf2cc64d ("net: marvell: prestera: add firmware v4.0 support"). With this fix applied: [ 88.499622] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.1.img firmware, fall-back to previous 4.0 version [ 88.511995] Prestera DX 0000:01:00.0: failed to request previous firmware: mrvl/prestera/mvsw_prestera_fw-v4.0.img [ 88.522403] Prestera DX: probe of 0000:01:00.0 failed with error -2 Fixes: 47f26018a414 ("net: marvell: prestera: try to load previous fw version") Signed-off-by: Jonas Gorski Acked-by: Elad Nachman Reviewed-by: Jesse Brandeburg Acked-by: Taras Chornyi Link: https://lore.kernel.org/r/20230802092357.163944-1-jonas.gorski@bisdn.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c index f328d957b2db..35857dc19542 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c @@ -727,7 +727,8 @@ pick_fw_ver: err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev); if (err) { - if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) { + if (ver_maj != PRESTERA_PREV_FW_MAJ_VER || + ver_min != PRESTERA_PREV_FW_MIN_VER) { ver_maj = PRESTERA_PREV_FW_MAJ_VER; ver_min = PRESTERA_PREV_FW_MIN_VER; -- cgit v1.2.3 From e6638094d7af6c7b9dcca05ad009e79e31b4f670 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:14:55 +0000 Subject: tcp_metrics: fix addr_same() helper Because v4 and v6 families use separate inetpeer trees (respectively net->ipv4.peers and net->ipv6.peers), inetpeer_addr_cmp(a, b) assumes a & b share the same family. tcp_metrics use a common hash table, where entries can have different families. We must therefore make sure to not call inetpeer_addr_cmp() if the families do not match. Fixes: d39d14ffa24c ("net: Add helper function to compare inetpeer addresses") Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230802131500.1478140-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 82f4575f9cd9..c4daf0aa2d4d 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -78,7 +78,7 @@ static void tcp_metric_set(struct tcp_metrics_block *tm, static bool addr_same(const struct inetpeer_addr *a, const struct inetpeer_addr *b) { - return inetpeer_addr_cmp(a, b) == 0; + return (a->family == b->family) && !inetpeer_addr_cmp(a, b); } struct tcpm_hash_bucket { -- cgit v1.2.3 From 949ad62a5d5311d36fce2e14fe5fed3f936da51c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:14:56 +0000 Subject: tcp_metrics: annotate data-races around tm->tcpm_stamp tm->tcpm_stamp can be read or written locklessly. Add needed READ_ONCE()/WRITE_ONCE() to document this. Also constify tcpm_check_stamp() dst argument. Fixes: 51c5d0c4b169 ("tcp: Maintain dynamic metrics in local cache.") Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230802131500.1478140-3-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index c4daf0aa2d4d..838616588796 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -97,7 +97,7 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, u32 msval; u32 val; - tm->tcpm_stamp = jiffies; + WRITE_ONCE(tm->tcpm_stamp, jiffies); val = 0; if (dst_metric_locked(dst, RTAX_RTT)) @@ -131,9 +131,15 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, #define TCP_METRICS_TIMEOUT (60 * 60 * HZ) -static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst) +static void tcpm_check_stamp(struct tcp_metrics_block *tm, + const struct dst_entry *dst) { - if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT))) + unsigned long limit; + + if (!tm) + return; + limit = READ_ONCE(tm->tcpm_stamp) + TCP_METRICS_TIMEOUT; + if (unlikely(time_after(jiffies, limit))) tcpm_suck_dst(tm, dst, false); } @@ -174,7 +180,8 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, oldest = deref_locked(tcp_metrics_hash[hash].chain); for (tm = deref_locked(oldest->tcpm_next); tm; tm = deref_locked(tm->tcpm_next)) { - if (time_before(tm->tcpm_stamp, oldest->tcpm_stamp)) + if (time_before(READ_ONCE(tm->tcpm_stamp), + READ_ONCE(oldest->tcpm_stamp))) oldest = tm; } tm = oldest; @@ -434,7 +441,7 @@ void tcp_update_metrics(struct sock *sk) tp->reordering); } } - tm->tcpm_stamp = jiffies; + WRITE_ONCE(tm->tcpm_stamp, jiffies); out_unlock: rcu_read_unlock(); } @@ -647,7 +654,7 @@ static int tcp_metrics_fill_info(struct sk_buff *msg, } if (nla_put_msecs(msg, TCP_METRICS_ATTR_AGE, - jiffies - tm->tcpm_stamp, + jiffies - READ_ONCE(tm->tcpm_stamp), TCP_METRICS_ATTR_PAD) < 0) goto nla_put_failure; -- cgit v1.2.3 From 285ce119a3c6c4502585936650143e54c8692788 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:14:57 +0000 Subject: tcp_metrics: annotate data-races around tm->tcpm_lock tm->tcpm_lock can be read or written locklessly. Add needed READ_ONCE()/WRITE_ONCE() to document this. Fixes: 51c5d0c4b169 ("tcp: Maintain dynamic metrics in local cache.") Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230802131500.1478140-4-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 838616588796..131fa3004969 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -59,7 +59,8 @@ static inline struct net *tm_net(struct tcp_metrics_block *tm) static bool tcp_metric_locked(struct tcp_metrics_block *tm, enum tcp_metric_index idx) { - return tm->tcpm_lock & (1 << idx); + /* Paired with WRITE_ONCE() in tcpm_suck_dst() */ + return READ_ONCE(tm->tcpm_lock) & (1 << idx); } static u32 tcp_metric_get(struct tcp_metrics_block *tm, @@ -110,7 +111,8 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, val |= 1 << TCP_METRIC_CWND; if (dst_metric_locked(dst, RTAX_REORDERING)) val |= 1 << TCP_METRIC_REORDERING; - tm->tcpm_lock = val; + /* Paired with READ_ONCE() in tcp_metric_locked() */ + WRITE_ONCE(tm->tcpm_lock, val); msval = dst_metric_raw(dst, RTAX_RTT); tm->tcpm_vals[TCP_METRIC_RTT] = msval * USEC_PER_MSEC; -- cgit v1.2.3 From 8c4d04f6b443869d25e59822f7cec88d647028a9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:14:58 +0000 Subject: tcp_metrics: annotate data-races around tm->tcpm_vals[] tm->tcpm_vals[] values can be read or written locklessly. Add needed READ_ONCE()/WRITE_ONCE() to document this, and force use of tcp_metric_get() and tcp_metric_set() Fixes: 51c5d0c4b169 ("tcp: Maintain dynamic metrics in local cache.") Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 131fa3004969..fd4ab7a51cef 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -63,17 +63,19 @@ static bool tcp_metric_locked(struct tcp_metrics_block *tm, return READ_ONCE(tm->tcpm_lock) & (1 << idx); } -static u32 tcp_metric_get(struct tcp_metrics_block *tm, +static u32 tcp_metric_get(const struct tcp_metrics_block *tm, enum tcp_metric_index idx) { - return tm->tcpm_vals[idx]; + /* Paired with WRITE_ONCE() in tcp_metric_set() */ + return READ_ONCE(tm->tcpm_vals[idx]); } static void tcp_metric_set(struct tcp_metrics_block *tm, enum tcp_metric_index idx, u32 val) { - tm->tcpm_vals[idx] = val; + /* Paired with READ_ONCE() in tcp_metric_get() */ + WRITE_ONCE(tm->tcpm_vals[idx], val); } static bool addr_same(const struct inetpeer_addr *a, @@ -115,13 +117,16 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, WRITE_ONCE(tm->tcpm_lock, val); msval = dst_metric_raw(dst, RTAX_RTT); - tm->tcpm_vals[TCP_METRIC_RTT] = msval * USEC_PER_MSEC; + tcp_metric_set(tm, TCP_METRIC_RTT, msval * USEC_PER_MSEC); msval = dst_metric_raw(dst, RTAX_RTTVAR); - tm->tcpm_vals[TCP_METRIC_RTTVAR] = msval * USEC_PER_MSEC; - tm->tcpm_vals[TCP_METRIC_SSTHRESH] = dst_metric_raw(dst, RTAX_SSTHRESH); - tm->tcpm_vals[TCP_METRIC_CWND] = dst_metric_raw(dst, RTAX_CWND); - tm->tcpm_vals[TCP_METRIC_REORDERING] = dst_metric_raw(dst, RTAX_REORDERING); + tcp_metric_set(tm, TCP_METRIC_RTTVAR, msval * USEC_PER_MSEC); + tcp_metric_set(tm, TCP_METRIC_SSTHRESH, + dst_metric_raw(dst, RTAX_SSTHRESH)); + tcp_metric_set(tm, TCP_METRIC_CWND, + dst_metric_raw(dst, RTAX_CWND)); + tcp_metric_set(tm, TCP_METRIC_REORDERING, + dst_metric_raw(dst, RTAX_REORDERING)); if (fastopen_clear) { tm->tcpm_fastopen.mss = 0; tm->tcpm_fastopen.syn_loss = 0; @@ -667,7 +672,7 @@ static int tcp_metrics_fill_info(struct sk_buff *msg, if (!nest) goto nla_put_failure; for (i = 0; i < TCP_METRIC_MAX_KERNEL + 1; i++) { - u32 val = tm->tcpm_vals[i]; + u32 val = tcp_metric_get(tm, i); if (!val) continue; -- cgit v1.2.3 From d5d986ce42c71a7562d32c4e21e026b0f87befec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:14:59 +0000 Subject: tcp_metrics: annotate data-races around tm->tcpm_net tm->tcpm_net can be read or written locklessly. Instead of changing write_pnet() and read_pnet() and potentially hurt performance, add the needed READ_ONCE()/WRITE_ONCE() in tm_net() and tcpm_new(). Fixes: 849e8a0ca8d5 ("tcp_metrics: Add a field tcpm_net and verify it matches on lookup") Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230802131500.1478140-6-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index fd4ab7a51cef..4fd274836a48 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -40,7 +40,7 @@ struct tcp_fastopen_metrics { struct tcp_metrics_block { struct tcp_metrics_block __rcu *tcpm_next; - possible_net_t tcpm_net; + struct net *tcpm_net; struct inetpeer_addr tcpm_saddr; struct inetpeer_addr tcpm_daddr; unsigned long tcpm_stamp; @@ -51,9 +51,10 @@ struct tcp_metrics_block { struct rcu_head rcu_head; }; -static inline struct net *tm_net(struct tcp_metrics_block *tm) +static inline struct net *tm_net(const struct tcp_metrics_block *tm) { - return read_pnet(&tm->tcpm_net); + /* Paired with the WRITE_ONCE() in tcpm_new() */ + return READ_ONCE(tm->tcpm_net); } static bool tcp_metric_locked(struct tcp_metrics_block *tm, @@ -197,7 +198,9 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, if (!tm) goto out_unlock; } - write_pnet(&tm->tcpm_net, net); + /* Paired with the READ_ONCE() in tm_net() */ + WRITE_ONCE(tm->tcpm_net, net); + tm->tcpm_saddr = *saddr; tm->tcpm_daddr = *daddr; -- cgit v1.2.3 From ddf251fa2bc1d3699eec0bae6ed0bc373b8fda79 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Aug 2023 13:15:00 +0000 Subject: tcp_metrics: fix data-race in tcpm_suck_dst() vs fastopen Whenever tcpm_new() reclaims an old entry, tcpm_suck_dst() would overwrite data that could be read from tcp_fastopen_cache_get() or tcp_metrics_fill_info(). We need to acquire fastopen_seqlock to maintain consistency. For newly allocated objects, tcpm_new() can switch to kzalloc() to avoid an extra fastopen_seqlock acquisition. Fixes: 1fe4c481ba63 ("net-tcp: Fast Open client - cookie cache") Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230802131500.1478140-7-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_metrics.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 4fd274836a48..99ac5efe244d 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -93,6 +93,7 @@ static struct tcpm_hash_bucket *tcp_metrics_hash __read_mostly; static unsigned int tcp_metrics_hash_log __read_mostly; static DEFINE_SPINLOCK(tcp_metrics_lock); +static DEFINE_SEQLOCK(fastopen_seqlock); static void tcpm_suck_dst(struct tcp_metrics_block *tm, const struct dst_entry *dst, @@ -129,11 +130,13 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, tcp_metric_set(tm, TCP_METRIC_REORDERING, dst_metric_raw(dst, RTAX_REORDERING)); if (fastopen_clear) { + write_seqlock(&fastopen_seqlock); tm->tcpm_fastopen.mss = 0; tm->tcpm_fastopen.syn_loss = 0; tm->tcpm_fastopen.try_exp = 0; tm->tcpm_fastopen.cookie.exp = false; tm->tcpm_fastopen.cookie.len = 0; + write_sequnlock(&fastopen_seqlock); } } @@ -194,7 +197,7 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, } tm = oldest; } else { - tm = kmalloc(sizeof(*tm), GFP_ATOMIC); + tm = kzalloc(sizeof(*tm), GFP_ATOMIC); if (!tm) goto out_unlock; } @@ -204,7 +207,7 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, tm->tcpm_saddr = *saddr; tm->tcpm_daddr = *daddr; - tcpm_suck_dst(tm, dst, true); + tcpm_suck_dst(tm, dst, reclaim); if (likely(!reclaim)) { tm->tcpm_next = tcp_metrics_hash[hash].chain; @@ -556,8 +559,6 @@ bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst) return ret; } -static DEFINE_SEQLOCK(fastopen_seqlock); - void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, struct tcp_fastopen_cookie *cookie) { -- cgit v1.2.3 From 3c50c8b240390907c9a33c86d25d850520db6dfa Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Thu, 3 Aug 2023 10:54:54 +0200 Subject: test/vsock: remove vsock_perf executable on `make clean` We forgot to add vsock_perf to the rm command in the `clean` target, so now we have a left over after `make clean` in tools/testing/vsock. Fixes: 8abbffd27ced ("test/vsock: vsock_perf utility") Cc: AVKrasnov@sberdevices.ru Signed-off-by: Stefano Garzarella Reviewed-by: Simon Horman Tested-by: Simon Horman # build-tested Link: https://lore.kernel.org/r/20230803085454.30897-1-sgarzare@redhat.com Signed-off-by: Jakub Kicinski --- tools/testing/vsock/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/vsock/Makefile b/tools/testing/vsock/Makefile index 43a254f0e14d..21a98ba565ab 100644 --- a/tools/testing/vsock/Makefile +++ b/tools/testing/vsock/Makefile @@ -8,5 +8,5 @@ vsock_perf: vsock_perf.o CFLAGS += -g -O2 -Werror -Wall -I. -I../../include -I../../../usr/include -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE -D_GNU_SOURCE .PHONY: all test clean clean: - ${RM} *.o *.d vsock_test vsock_diag_test + ${RM} *.o *.d vsock_test vsock_diag_test vsock_perf -include *.d -- cgit v1.2.3 From 4fdfaef71fced490835145631a795497646f4555 Mon Sep 17 00:00:00 2001 From: Douglas Miller Date: Wed, 2 Aug 2023 13:32:41 -0400 Subject: IB/hfi1: Fix possible panic during hotplug remove During hotplug remove it is possible that the update counters work might be pending, and may run after memory has been freed. Cancel the update counters work before freeing memory. Fixes: 7724105686e7 ("IB/hfi1: add driver files") Signed-off-by: Douglas Miller Signed-off-by: Dennis Dalessandro Link: https://lore.kernel.org/r/169099756100.3927190.15284930454106475280.stgit@awfm-02.cornelisnetworks.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hfi1/chip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 9dbb89e9f4af..baaa4406d5e6 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -12307,6 +12307,7 @@ static void free_cntrs(struct hfi1_devdata *dd) if (dd->synth_stats_timer.function) del_timer_sync(&dd->synth_stats_timer); + cancel_work_sync(&dd->update_cntr_work); ppd = (struct hfi1_pportdata *)(dd + 1); for (i = 0; i < dd->num_pports; i++, ppd++) { kfree(ppd->cntrs); -- cgit v1.2.3 From 0765c5f293357ee43eca72e27c3547f9d99ac355 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 2 Aug 2023 11:28:43 -0700 Subject: MAINTAINERS: update TUN/TAP maintainers Willem and Jason have agreed to take over the maintainer duties for TUN/TAP, thank you! There's an existing entry for TUN/TAP which only covers the user mode Linux implementation. Since we haven't heard from Maxim on the list for almost a decade, extend that entry and take it over, rather than adding a new one. Acked-by: Willem de Bruijn Acked-by: Jason Wang Link: https://lore.kernel.org/r/20230802182843.4193099-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1085dfb35777..8f93c48f6931 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21670,11 +21670,14 @@ S: Orphan F: drivers/net/ethernet/dec/tulip/ TUN/TAP driver -M: Maxim Krasnyansky +M: Willem de Bruijn +M: Jason Wang S: Maintained W: http://vtun.sourceforge.net/tun F: Documentation/networking/tuntap.rst F: arch/um/os-Linux/drivers/ +F: drivers/net/tap.c +F: drivers/net/tun.c TURBOCHANNEL SUBSYSTEM M: "Maciej W. Rozycki" -- cgit v1.2.3 From 1696ec8654016dad3b1baf6c024303e584400453 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 2 Aug 2023 10:40:29 -0700 Subject: mISDN: Update parameter type of dsp_cmx_send() When booting a kernel with CONFIG_MISDN_DSP=y and CONFIG_CFI_CLANG=y, there is a failure when dsp_cmx_send() is called indirectly from call_timer_fn(): [ 0.371412] CFI failure at call_timer_fn+0x2f/0x150 (target: dsp_cmx_send+0x0/0x530; expected type: 0x92ada1e9) The function pointer prototype that call_timer_fn() expects is void (*fn)(struct timer_list *) whereas dsp_cmx_send() has a parameter type of 'void *', which causes the control flow integrity checks to fail because the parameter types do not match. Change dsp_cmx_send()'s parameter type to be 'struct timer_list' to match the expected prototype. The argument is unused anyways, so this has no functional change, aside from avoiding the CFI failure. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202308020936.58787e6c-oliver.sang@intel.com Signed-off-by: Nathan Chancellor Reviewed-by: Sami Tolvanen Reviewed-by: Kees Cook Fixes: e313ac12eb13 ("mISDN: Convert timers to use timer_setup()") Link: https://lore.kernel.org/r/20230802-fix-dsp_cmx_send-cfi-failure-v1-1-2f2e79b0178d@kernel.org Signed-off-by: Jakub Kicinski --- drivers/isdn/mISDN/dsp.h | 2 +- drivers/isdn/mISDN/dsp_cmx.c | 2 +- drivers/isdn/mISDN/dsp_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index fa09d511a8ed..baf31258f5c9 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -247,7 +247,7 @@ extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp); extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); -extern void dsp_cmx_send(void *arg); +extern void dsp_cmx_send(struct timer_list *arg); extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); extern int dsp_cmx_del_conf_member(struct dsp *dsp); extern int dsp_cmx_del_conf(struct dsp_conf *conf); diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 357b87592eb4..61cb45c5d0d8 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1614,7 +1614,7 @@ static u16 dsp_count; /* last sample count */ static int dsp_count_valid; /* if we have last sample count */ void -dsp_cmx_send(void *arg) +dsp_cmx_send(struct timer_list *arg) { struct dsp_conf *conf; struct dsp_conf_member *member; diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 386084530c2f..fae95f166688 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -1195,7 +1195,7 @@ static int __init dsp_init(void) } /* set sample timer */ - timer_setup(&dsp_spl_tl, (void *)dsp_cmx_send, 0); + timer_setup(&dsp_spl_tl, dsp_cmx_send, 0); dsp_spl_tl.expires = jiffies + dsp_tics; dsp_spl_jiffies = dsp_spl_tl.expires; add_timer(&dsp_spl_tl); -- cgit v1.2.3 From 3c6bd1b7e2043fb00ce6b622709d176609431406 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 2 Aug 2023 10:52:22 +0200 Subject: Revert "drm/bridge: lt9611: Do not generate HFP/HBP/HSA and EOT packet" This reverts commit 8ddce13ae696 ("drm/bridge: lt9611: Do not generate HFP/HBP/HSA and EOT packet") to fix display regression on the Dragonboard 845c (SDM845) devboard. There's a mismatch on the real action of the following flags: - MIPI_DSI_MODE_VIDEO_NO_HSA - MIPI_DSI_MODE_VIDEO_NO_HFP - MIPI_DSI_MODE_VIDEO_NO_HBP which leads to a non-working display on qcom platforms. Cc: Marek Vasut Cc: Robert Foss Cc: Jagan Teki Cc: Dmitry Baryshkov Cc: Abhinav Kumar Fixes: 8ddce13ae696 ("drm/bridge: lt9611: Do not generate HFP/HBP/HSA and EOT packet") Reported-by: Amit Pundir Closes: https://lore.kernel.org/r/CAMi1Hd0TD=2z_=bcDrht3H_wiLvAFcv8Z-U_r_KUOoeMc6UMjw@mail.gmail.com/ Tested-by: Amit Pundir Acked-by: Dmitry Baryshkov #fix db845c [narmstrong: fixed commit message format] Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230802-revert-do-not-generate-hfp-hbp-hsa-eot-packet-v1-1-f8a20084e15a@linaro.org --- drivers/gpu/drm/bridge/lontium-lt9611.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 5163e5224aad..9663601ce098 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -774,9 +774,7 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA | - MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP | - MIPI_DSI_MODE_NO_EOT_PACKET; + MIPI_DSI_MODE_VIDEO_HSE; ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { -- cgit v1.2.3 From e58f30246c35c126c7571065b33bee4b3b1d2ef8 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Wed, 2 Aug 2023 14:13:46 -0500 Subject: net: phy: at803x: fix the wol setting functions In commit 7beecaf7d507 ("net: phy: at803x: improve the WOL feature"), it seems not correct to use a wol_en bit in a 1588 Control Register which is only available on AR8031/AR8033(share the same phy_id) to determine if WoL is enabled. Change it back to use AT803X_INTR_ENABLE_WOL for determining the WoL status which is applicable on all chips supporting wol. Also update the at803x_set_wol() function to only update the 1588 register on chips having it. After this change, disabling wol at probe from commit d7cd5e06c9dd ("net: phy: at803x: disable WOL at probe") is no longer needed. Change it to just disable the WoL bit in 1588 register for AR8031/AR8033 to be aligned with AT803X_INTR_ENABLE_WOL in probe. Fixes: 7beecaf7d507 ("net: phy: at803x: improve the WOL feature") Signed-off-by: Li Yang Reviewed-by: Viorel Suman Reviewed-by: Wei Fang Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index c1f307d90518..9c2c2e2ee94b 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -459,21 +459,27 @@ static int at803x_set_wol(struct phy_device *phydev, phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); - /* Enable WOL function */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL, - 0, AT803X_WOL_EN); - if (ret) - return ret; + /* Enable WOL function for 1588 */ + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + 0, AT803X_WOL_EN); + if (ret) + return ret; + } /* Enable WOL interrupt */ ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); if (ret) return ret; } else { - /* Disable WoL function */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL, - AT803X_WOL_EN, 0); - if (ret) - return ret; + /* Disable WoL function for 1588 */ + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); + if (ret) + return ret; + } /* Disable WOL interrupt */ ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); if (ret) @@ -508,11 +514,11 @@ static void at803x_get_wol(struct phy_device *phydev, wol->supported = WAKE_MAGIC; wol->wolopts = 0; - value = phy_read_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL); + value = phy_read(phydev, AT803X_INTR_ENABLE); if (value < 0) return; - if (value & AT803X_WOL_EN) + if (value & AT803X_INTR_ENABLE_WOL) wol->wolopts |= WAKE_MAGIC; } @@ -858,9 +864,6 @@ static int at803x_probe(struct phy_device *phydev) if (phydev->drv->phy_id == ATH8031_PHY_ID) { int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); int mode_cfg; - struct ethtool_wolinfo wol = { - .wolopts = 0, - }; if (ccr < 0) return ccr; @@ -877,12 +880,14 @@ static int at803x_probe(struct phy_device *phydev) break; } - /* Disable WOL by default */ - ret = at803x_set_wol(phydev, &wol); - if (ret < 0) { - phydev_err(phydev, "failed to disable WOL on probe: %d\n", ret); + /* Disable WoL in 1588 register which is enabled + * by default + */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); + if (ret) return ret; - } } return 0; -- cgit v1.2.3 From d7791cec2304aea22eb2ada944e4d467302f5bfe Mon Sep 17 00:00:00 2001 From: Li Yang Date: Wed, 2 Aug 2023 14:13:47 -0500 Subject: net: phy: at803x: remove set/get wol callbacks for AR8032 Since the AR8032 part does not support wol, remove related callbacks from it. Fixes: 5800091a2061 ("net: phy: at803x: add support for AR8032 PHY") Signed-off-by: Li Yang Cc: David Bauer Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 9c2c2e2ee94b..8a77ec33b417 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -2064,8 +2064,6 @@ static struct phy_driver at803x_driver[] = { .flags = PHY_POLL_CABLE_TEST, .config_init = at803x_config_init, .link_change_notify = at803x_link_change_notify, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, .suspend = at803x_suspend, .resume = at803x_resume, /* PHY_BASIC_FEATURES */ -- cgit v1.2.3 From 1d54134df47684ee29d4d4bbe28174a4282389e0 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 3 Aug 2023 15:50:28 +0800 Subject: ASoC: SOF: mediatek: mt8186 modify dram type as non-cache To prevent incorrect access between the host and DSP sides, we need to modify DRAM as a non-cache memory type. Additionally, we can retrieve the size of shared DMA from the device tree. Signed-off-by: Trevor Wu Reviewed-by: Yaochun Hung Reviewed-by: Kuan-Hsun Cheng Link: https://lore.kernel.org/r/20230803075028.32170-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 40 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 3e0ea0e109e2..f587edf9e0a7 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -111,6 +111,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) dev_dbg(dev, "DMA %pR\n", &res); + adsp->pa_shared_dram = (phys_addr_t)res.start; + adsp->shared_size = resource_size(&res); + if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_shared_dram); + return -EINVAL; + } + ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -244,23 +252,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) { struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; - u32 shared_size; /* remap shared-dram base to be non-cachable */ - shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; - adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; - if (adsp->va_dram) { - adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; - } else { - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "ioremap failed for shared DRAM\n"); - return -ENOMEM; - } + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + adsp->shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "failed to ioremap base %pa size %#x\n", + adsp->shared_dram, adsp->shared_size); + return -ENOMEM; } - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, shared_size); + + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", + adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); return 0; } @@ -307,9 +310,12 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) return -ENOMEM; } - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, - priv->adsp->pa_dram, - priv->adsp->dramsize); + priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM]; + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", &priv->adsp->pa_dram, priv->adsp->dramsize); -- cgit v1.2.3 From 6a41c3a1606089bdf7f8da2b267d1d82fb32b378 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 3 Aug 2023 18:55:05 -0300 Subject: ASoC: dt-bindings: wlf,wm8960: Describe the power supplies WM8960 has the following power supplies: - AVDD - DBVDD - DCVDD - SPKVDD1 - SPKVDD1 Add them to bindings to improve the hardware description. Signed-off-by: Fabio Estevam Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230803215506.142922-1-festevam@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8960.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml index ee8eba7f0104..62e62c335d07 100644 --- a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml @@ -26,6 +26,21 @@ properties: '#sound-dai-cells': const: 0 + AVDD-supply: + description: Analogue supply. + + DBVDD-supply: + description: Digital Buffer Supply. + + DCVDD-supply: + description: Digital Core Supply. + + SPKVDD1-supply: + description: Supply for speaker drivers 1. + + SPKVDD2-supply: + description: Supply for speaker drivers 2. + wlf,capless: type: boolean description: @@ -84,5 +99,10 @@ examples: wlf,hp-cfg = <3 2 3>; wlf,gpio-cfg = <1 3>; wlf,shared-lrclk; + DCVDD-supply = <®_audio>; + DBVDD-supply = <®_audio>; + AVDD-supply = <®_audio>; + SPKVDD1-supply = <®_audio>; + SPKVDD2-supply = <®_audio>; }; }; -- cgit v1.2.3 From 422f10adc3eb5a7ff8567bf6e6590a4e4fa756c3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 3 Aug 2023 18:55:06 -0300 Subject: ASoC: wm8960: Add support for the power supplies WM8960 has the following power supplies: - AVDD - DBVDD - DCVDD - SPKVDD1 - SPKVDD1 Add support for them. Signed-off-by: Fabio Estevam Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230803215506.142922-2-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d4bc97088354..0a50180750e8 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg) } } +#define WM8960_NUM_SUPPLIES 5 +static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD", + "SPKVDD1", + "SPKVDD2", +}; + struct wm8960_priv { struct clk *mclk; struct regmap *regmap; @@ -137,6 +146,7 @@ struct wm8960_priv { bool is_stream_in_use[2]; struct wm8960_data pdata; ktime_t dsch_start; + struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES]; }; #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) @@ -1417,6 +1427,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; + unsigned int i; int ret; u8 val; @@ -1439,6 +1450,23 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) } } + for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++) + wm8960->supplies[i].supply = wm8960_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); @@ -1505,7 +1533,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) } static void wm8960_i2c_remove(struct i2c_client *client) -{} +{ + struct wm8960_priv *wm8960 = i2c_get_clientdata(client); + + regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies); +} static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, -- cgit v1.2.3 From 9606cda3501ae5d1a865d839ee5dbae9552a7b37 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 4 Aug 2023 16:54:02 +0800 Subject: ASoC: ti: davinci-evm: simplify the code with module_platform_driver The init/exit() of driver only calls platform_driver_register/unregister, it can be simpilfied with module_platform_driver. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230804085402.1328033-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 983d69b951b0..544cb3da50eb 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -257,18 +257,7 @@ static struct platform_driver davinci_evm_driver = { }, }; -static int __init evm_init(void) -{ - return platform_driver_register(&davinci_evm_driver); -} - -static void __exit evm_exit(void) -{ - platform_driver_unregister(&davinci_evm_driver); -} - -module_init(evm_init); -module_exit(evm_exit); +module_platform_driver(davinci_evm_driver); MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); -- cgit v1.2.3 From 4270d2b4845e820b274702bfc2a7140f69e4d19d Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 12 Jul 2023 08:57:22 +0000 Subject: usb: typec: tcpm: Fix response to vsafe0V event Do not transition to SNK_UNATTACHED state when receiving vsafe0v event while in SNK_HARD_RESET_WAIT_VBUS. Ignore VBUS off events as well as in some platforms VBUS off can be signalled more than once. [143515.364753] Requesting mux state 1, usb-role 2, orientation 2 [143515.365520] pending state change SNK_HARD_RESET_SINK_OFF -> SNK_HARD_RESET_SINK_ON @ 650 ms [rev3 HARD_RESET] [143515.632281] CC1: 0 -> 0, CC2: 3 -> 0 [state SNK_HARD_RESET_SINK_OFF, polarity 1, disconnected] [143515.637214] VBUS on [143515.664985] VBUS off [143515.664992] state change SNK_HARD_RESET_SINK_OFF -> SNK_HARD_RESET_WAIT_VBUS [rev3 HARD_RESET] [143515.665564] VBUS VSAFE0V [143515.665566] state change SNK_HARD_RESET_WAIT_VBUS -> SNK_UNATTACHED [rev3 HARD_RESET] Fixes: 28b43d3d746b ("usb: typec: tcpm: Introduce vsafe0v for vbus") Cc: Signed-off-by: Badhri Jagan Sridharan Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230712085722.1414743-1-badhri@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 829d75ebab42..cc1d83926497 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -5349,6 +5349,10 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) /* Do nothing, vbus drop expected */ break; + case SNK_HARD_RESET_WAIT_VBUS: + /* Do nothing, its OK to receive vbus off events */ + break; + default: if (port->pwr_role == TYPEC_SINK && port->attached) tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port)); @@ -5395,6 +5399,9 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port) case SNK_DEBOUNCED: /*Do nothing, still waiting for VSAFE5V for connect */ break; + case SNK_HARD_RESET_WAIT_VBUS: + /* Do nothing, its OK to receive vbus off events */ + break; default: if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled) tcpm_set_state(port, SNK_UNATTACHED, 0); -- cgit v1.2.3 From 5a5ccd61cfd76156cb3e0373c300c509d05448ce Mon Sep 17 00:00:00 2001 From: RD Babiera Date: Wed, 26 Jul 2023 02:09:02 +0000 Subject: usb: typec: altmodes/displayport: Signal hpd when configuring pin assignment When connecting to some DisplayPort partners, the initial status update after entering DisplayPort Alt Mode notifies that the DFP_D/UFP_D is not in the connected state. This leads to sending a configure message that keeps the device in USB mode. The port partner then sets DFP_D/UFP_D to the connected state and HPD to high in the same Attention message. Currently, the HPD signal is dropped in order to handle configuration. This patch saves changes to the HPD signal when the device chooses to configure during dp_altmode_status_update, and invokes sysfs_notify if necessary for HPD after configuring. Fixes: 0e3bb7d6894d ("usb: typec: Add driver for DisplayPort alternate mode") Cc: stable@vger.kernel.org Signed-off-by: RD Babiera Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230726020903.1409072-1-rdbabiera@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/displayport.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 66de880b28d0..cdf8261e22db 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -60,6 +60,7 @@ struct dp_altmode { enum dp_state state; bool hpd; + bool pending_hpd; struct mutex lock; /* device lock */ struct work_struct work; @@ -144,8 +145,13 @@ static int dp_altmode_status_update(struct dp_altmode *dp) dp->state = DP_STATE_EXIT; } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) { ret = dp_altmode_configure(dp, con); - if (!ret) + if (!ret) { dp->state = DP_STATE_CONFIGURE; + if (dp->hpd != hpd) { + dp->hpd = hpd; + dp->pending_hpd = true; + } + } } else { if (dp->hpd != hpd) { drm_connector_oob_hotplug_event(dp->connector_fwnode); @@ -161,6 +167,16 @@ static int dp_altmode_configured(struct dp_altmode *dp) { sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration"); sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment"); + /* + * If the DFP_D/UFP_D sends a change in HPD when first notifying the + * DisplayPort driver that it is connected, then we wait until + * configuration is complete to signal HPD. + */ + if (dp->pending_hpd) { + drm_connector_oob_hotplug_event(dp->connector_fwnode); + sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); + dp->pending_hpd = false; + } return dp_altmode_notify(dp); } -- cgit v1.2.3 From 348359e7c232adc153ed7ec9a157f22d68d29860 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 18 Jul 2023 23:40:05 +0200 Subject: usb: typec: nb7vpq904m: Add an error handling path in nb7vpq904m_probe() In case of error in the nb7vpq904m_probe() probe function, some resources need to be freed, as already done in the remove function. Add the missing error handling path and adjust code accordingly. Fixes: 88d8f3ac9c67 ("usb: typec: add support for the nb7vpq904m Type-C Linear Redriver") Signed-off-by: Christophe JAILLET Reviewed-by: Neil Armstrong Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/9118954765821ea9f1179883602b4eca63e91749.1689716381.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/nb7vpq904m.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/usb/typec/mux/nb7vpq904m.c b/drivers/usb/typec/mux/nb7vpq904m.c index 80e580d50129..4d1122d95013 100644 --- a/drivers/usb/typec/mux/nb7vpq904m.c +++ b/drivers/usb/typec/mux/nb7vpq904m.c @@ -463,16 +463,18 @@ static int nb7vpq904m_probe(struct i2c_client *client) ret = nb7vpq904m_register_bridge(nb7); if (ret) - return ret; + goto err_disable_gpio; sw_desc.drvdata = nb7; sw_desc.fwnode = dev->fwnode; sw_desc.set = nb7vpq904m_sw_set; nb7->sw = typec_switch_register(dev, &sw_desc); - if (IS_ERR(nb7->sw)) - return dev_err_probe(dev, PTR_ERR(nb7->sw), - "Error registering typec switch\n"); + if (IS_ERR(nb7->sw)) { + ret = dev_err_probe(dev, PTR_ERR(nb7->sw), + "Error registering typec switch\n"); + goto err_disable_gpio; + } retimer_desc.drvdata = nb7; retimer_desc.fwnode = dev->fwnode; @@ -480,12 +482,21 @@ static int nb7vpq904m_probe(struct i2c_client *client) nb7->retimer = typec_retimer_register(dev, &retimer_desc); if (IS_ERR(nb7->retimer)) { - typec_switch_unregister(nb7->sw); - return dev_err_probe(dev, PTR_ERR(nb7->retimer), - "Error registering typec retimer\n"); + ret = dev_err_probe(dev, PTR_ERR(nb7->retimer), + "Error registering typec retimer\n"); + goto err_switch_unregister; } return 0; + +err_switch_unregister: + typec_switch_unregister(nb7->sw); + +err_disable_gpio: + gpiod_set_value(nb7->enable_gpio, 0); + regulator_disable(nb7->vcc_supply); + + return ret; } static void nb7vpq904m_remove(struct i2c_client *client) -- cgit v1.2.3 From ef7c4d8a90c64bac294363c6f67eb98246a162a2 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 31 Jul 2023 16:12:10 +0300 Subject: usb: typec: mux: intel: Add dependency on USB_COMMON This fixes an undefined reference to `usb_debug_root' issue when USB_COMMON is not enabled. Fixes: 0a453dc9f260 ("usb: typec: intel_pmc_mux: Expose IOM port status to debugfs") Reported-by: Randy Dunlap Closes: https://lore.kernel.org/lkml/c3bb8781-676d-2448-cfbb-62e29f1f570b@infradead.org/ Cc: Rajat Khandelwal Signed-off-by: Heikki Krogerus Tested-by: Randy Dunlap # build-tested Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20230731131210.43158-1-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 784b9d8107e9..65da61150ba7 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -29,6 +29,7 @@ config TYPEC_MUX_INTEL_PMC tristate "Intel PMC mux control" depends on ACPI depends on INTEL_SCU_IPC + select USB_COMMON select USB_ROLE_SWITCH help Driver for USB muxes controlled by Intel PMC FW. Intel PMC FW can -- cgit v1.2.3 From 65dadb2beeb7360232b09ebc4585b54475dfee06 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 29 Jul 2023 10:59:38 -0400 Subject: USB: Gadget: core: Help prevent panic during UVC unconfigure Avichal Rakesh reported a kernel panic that occurred when the UVC gadget driver was removed from a gadget's configuration. The panic involves a somewhat complicated interaction between the kernel driver and a userspace component (as described in the Link tag below), but the analysis did make one thing clear: The Gadget core should accomodate gadget drivers calling usb_gadget_deactivate() as part of their unbind procedure. Currently this doesn't work. gadget_unbind_driver() calls driver->unbind() while holding the udc->connect_lock mutex, and usb_gadget_deactivate() attempts to acquire that mutex, which will result in a deadlock. The simple fix is for gadget_unbind_driver() to release the mutex when invoking the ->unbind() callback. There is no particular reason for it to be holding the mutex at that time, and the mutex isn't held while the ->bind() callback is invoked. So we'll drop the mutex before performing the unbind callback and reacquire it afterward. We'll also add a couple of comments to usb_gadget_activate() and usb_gadget_deactivate(). Because they run in process context they must not be called from a gadget driver's ->disconnect() callback, which (according to the kerneldoc for struct usb_gadget_driver in include/linux/usb/gadget.h) may run in interrupt context. This may help prevent similar bugs from arising in the future. Reported-and-tested-by: Avichal Rakesh Signed-off-by: Alan Stern Fixes: 286d9975a838 ("usb: gadget: udc: core: Prevent soft_connect_store() race") Link: https://lore.kernel.org/linux-usb/4d7aa3f4-22d9-9f5a-3d70-1bd7148ff4ba@google.com/ Cc: Badhri Jagan Sridharan Cc: Link: https://lore.kernel.org/r/48b2f1f1-0639-46bf-bbfc-98cb05a24914@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index cd58f2a4e7f3..7d49d8a0b00c 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -822,6 +822,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_disconnect); * usb_gadget_activate() is called. For example, user mode components may * need to be activated before the system can talk to hosts. * + * This routine may sleep; it must not be called in interrupt context + * (such as from within a gadget driver's disconnect() callback). + * * Returns zero on success, else negative errno. */ int usb_gadget_deactivate(struct usb_gadget *gadget) @@ -860,6 +863,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_deactivate); * This routine activates gadget which was previously deactivated with * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. * + * This routine may sleep; it must not be called in interrupt context. + * * Returns zero on success, else negative errno. */ int usb_gadget_activate(struct usb_gadget *gadget) @@ -1638,7 +1643,11 @@ static void gadget_unbind_driver(struct device *dev) usb_gadget_disable_async_callbacks(udc); if (gadget->irq) synchronize_irq(gadget->irq); + mutex_unlock(&udc->connect_lock); + udc->driver->unbind(gadget); + + mutex_lock(&udc->connect_lock); usb_gadget_udc_stop_locked(udc); mutex_unlock(&udc->connect_lock); -- cgit v1.2.3 From 8e21a620c7e6e00347ade1a6ed4967b359eada5a Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 1 Aug 2023 14:33:52 +0530 Subject: usb: common: usb-conn-gpio: Prevent bailing out if initial role is none Currently if we bootup a device without cable connected, then usb-conn-gpio won't call set_role() because last_role is same as current role. This happens since last_role gets initialised to zero during the probe. To avoid this, add a new flag initial_detection into struct usb_conn_info, which prevents bailing out during initial detection. Cc: # 5.4 Fixes: 4602f3bff266 ("usb: common: add USB GPIO based connection detection driver") Signed-off-by: Prashanth K Tested-by: AngeloGioacchino Del Regno Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/1690880632-12588-1-git-send-email-quic_prashk@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/common/usb-conn-gpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 766005d20bae..501e8bc9738e 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -42,6 +42,7 @@ struct usb_conn_info { struct power_supply_desc desc; struct power_supply *charger; + bool initial_detection; }; /* @@ -86,11 +87,13 @@ static void usb_conn_detect_cable(struct work_struct *work) dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n", usb_role_string(info->last_role), usb_role_string(role), id, vbus); - if (info->last_role == role) { + if (!info->initial_detection && info->last_role == role) { dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role)); return; } + info->initial_detection = false; + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); @@ -258,6 +261,7 @@ static int usb_conn_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); /* Perform initial detection */ + info->initial_detection = true; usb_conn_queue_dwork(info, 0); return 0; -- cgit v1.2.3 From a6ff6e7a9dd69364547751db0f626a10a6d628d2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 2 Aug 2023 13:49:02 -0400 Subject: usb-storage: alauda: Fix uninit-value in alauda_check_media() Syzbot got KMSAN to complain about access to an uninitialized value in the alauda subdriver of usb-storage: BUG: KMSAN: uninit-value in alauda_transport+0x462/0x57f0 drivers/usb/storage/alauda.c:1137 CPU: 0 PID: 12279 Comm: usb-storage Not tainted 5.3.0-rc7+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x191/0x1f0 lib/dump_stack.c:113 kmsan_report+0x13a/0x2b0 mm/kmsan/kmsan_report.c:108 __msan_warning+0x73/0xe0 mm/kmsan/kmsan_instr.c:250 alauda_check_media+0x344/0x3310 drivers/usb/storage/alauda.c:460 The problem is that alauda_check_media() doesn't verify that its USB transfer succeeded before trying to use the received data. What should happen if the transfer fails isn't entirely clear, but a reasonably conservative approach is to pretend that no media is present. A similar problem exists in a usb_stor_dbg() call in alauda_get_media_status(). In this case, when an error occurs the call is redundant, because usb_stor_ctrl_transfer() already will print a debugging message. Finally, unrelated to the uninitialized memory access, is the fact that alauda_check_media() performs DMA to a buffer on the stack. Fortunately usb-storage provides a general purpose DMA-able buffer for uses like this. We'll use it instead. Reported-and-tested-by: syzbot+e7d46eb426883fb97efd@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/0000000000007d25ff059457342d@google.com/T/ Suggested-by: Christophe JAILLET Signed-off-by: Alan Stern Fixes: e80b0fade09e ("[PATCH] USB Storage: add alauda support") Cc: Link: https://lore.kernel.org/r/693d5d5e-f09b-42d0-8ed9-1f96cd30bcce@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/alauda.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 5e912dd29b4c..115f05a6201a 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -318,7 +318,8 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data) rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, command, 0xc0, 0, 1, data, 2); - usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]); + if (rc == USB_STOR_XFER_GOOD) + usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]); return rc; } @@ -454,9 +455,14 @@ static int alauda_init_media(struct us_data *us) static int alauda_check_media(struct us_data *us) { struct alauda_info *info = (struct alauda_info *) us->extra; - unsigned char status[2]; + unsigned char *status = us->iobuf; + int rc; - alauda_get_media_status(us, status); + rc = alauda_get_media_status(us, status); + if (rc != USB_STOR_XFER_GOOD) { + status[0] = 0xF0; /* Pretend there's no media */ + status[1] = 0; + } /* Check for no media or door open */ if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10) -- cgit v1.2.3 From 3ddaa6a274578e23745b7466346fc2650df8f959 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Tue, 1 Aug 2023 12:26:58 -0700 Subject: usb: dwc3: Properly handle processing of pending events If dwc3 is runtime suspended we defer processing the event buffer until resume, by setting the pending_events flag. Set this flag before triggering resume to avoid race with the runtime resume callback. While handling the pending events, in addition to checking the event buffer we also need to process it. Handle this by explicitly calling dwc3_thread_interrupt(). Also balance the runtime pm get() operation that triggered this processing. Cc: stable@vger.kernel.org Fixes: fc8bb91bc83e ("usb: dwc3: implement runtime PM") Signed-off-by: Elson Roy Serrao Acked-by: Thinh Nguyen Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230801192658.19275-1-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5fd067151fbf..858fe4c299b7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4455,9 +4455,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) u32 count; if (pm_runtime_suspended(dwc->dev)) { + dwc->pending_events = true; + /* + * Trigger runtime resume. The get() function will be balanced + * after processing the pending events in dwc3_process_pending + * events(). + */ pm_runtime_get(dwc->dev); disable_irq_nosync(dwc->irq_gadget); - dwc->pending_events = true; return IRQ_HANDLED; } @@ -4718,6 +4723,8 @@ void dwc3_gadget_process_pending_events(struct dwc3 *dwc) { if (dwc->pending_events) { dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf); + dwc3_thread_interrupt(dwc->irq_gadget, dwc->ev_buf); + pm_runtime_put(dwc->dev); dwc->pending_events = false; enable_irq(dwc->irq_gadget); } -- cgit v1.2.3 From 596a5123cc782d458b057eb3837e66535cd0befa Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 22 Jun 2023 14:59:12 +0300 Subject: thunderbolt: Fix memory leak in tb_handle_dp_bandwidth_request() The memory allocated in tb_queue_dp_bandwidth_request() needs to be released once the request is handled to avoid leaking it. Fixes: 6ce3563520be ("thunderbolt: Add support for DisplayPort bandwidth allocation mode") Cc: stable@vger.kernel.org Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 62b26b7998fd..3fb4553a6442 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -1964,6 +1964,8 @@ unlock: pm_runtime_mark_last_busy(&tb->dev); pm_runtime_put_autosuspend(&tb->dev); + + kfree(ev); } static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port) -- cgit v1.2.3 From adb9743d6a08778b78d62d16b4230346d3508986 Mon Sep 17 00:00:00 2001 From: Qi Zheng Date: Sun, 25 Jun 2023 15:49:37 +0000 Subject: binder: fix memory leak in binder_init() In binder_init(), the destruction of binder_alloc_shrinker_init() is not performed in the wrong path, which will cause memory leaks. So this commit introduces binder_alloc_shrinker_exit() and calls it in the wrong path to fix that. Signed-off-by: Qi Zheng Acked-by: Carlos Llamas Fixes: f2517eb76f1f ("android: binder: Add global lru shrinker to binder") Cc: stable Link: https://lore.kernel.org/r/20230625154937.64316-1-qi.zheng@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 1 + drivers/android/binder_alloc.c | 6 ++++++ drivers/android/binder_alloc.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 486c8271cab7..d720f93d8b19 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -6617,6 +6617,7 @@ err_init_binder_device_failed: err_alloc_device_names_failed: debugfs_remove_recursive(binder_debugfs_dir_entry_root); + binder_alloc_shrinker_exit(); return ret; } diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 662a2a2e2e84..e3db8297095a 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -1087,6 +1087,12 @@ int binder_alloc_shrinker_init(void) return ret; } +void binder_alloc_shrinker_exit(void) +{ + unregister_shrinker(&binder_shrinker); + list_lru_destroy(&binder_alloc_lru); +} + /** * check_buffer() - verify that buffer/offset is safe to access * @alloc: binder_alloc for this proc diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 138d1d5af9ce..dc1e2b01dd64 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -129,6 +129,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, int pid); extern void binder_alloc_init(struct binder_alloc *alloc); extern int binder_alloc_shrinker_init(void); +extern void binder_alloc_shrinker_exit(void); extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern struct binder_buffer * binder_alloc_prepare_to_free(struct binder_alloc *alloc, -- cgit v1.2.3 From 101bd907b4244a726980ee67f95ed9cafab6ff7a Mon Sep 17 00:00:00 2001 From: Ricky WU Date: Tue, 25 Jul 2023 09:10:54 +0000 Subject: misc: rtsx: judge ASPM Mode to set PETXCFG Reg ASPM Mode is ASPM_MODE_CFG need to judge the value of clkreq_0 to set HIGH or LOW, if the ASPM Mode is ASPM_MODE_REG always set to HIGH during the initialization. Cc: stable@vger.kernel.org Signed-off-by: Ricky Wu Link: https://lore.kernel.org/r/52906c6836374c8cb068225954c5543a@realtek.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rts5227.c | 2 +- drivers/misc/cardreader/rts5228.c | 18 ------------------ drivers/misc/cardreader/rts5249.c | 3 +-- drivers/misc/cardreader/rts5260.c | 18 ------------------ drivers/misc/cardreader/rts5261.c | 18 ------------------ drivers/misc/cardreader/rtsx_pcr.c | 5 ++++- 6 files changed, 6 insertions(+), 58 deletions(-) diff --git a/drivers/misc/cardreader/rts5227.c b/drivers/misc/cardreader/rts5227.c index d676cf63a966..3dae5e3a1697 100644 --- a/drivers/misc/cardreader/rts5227.c +++ b/drivers/misc/cardreader/rts5227.c @@ -195,7 +195,7 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) } } - if (option->force_clkreq_0) + if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); else diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index cfebad51d1d8..f4ab09439da7 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -435,17 +435,10 @@ static void rts5228_init_from_cfg(struct rtsx_pcr *pcr) option->ltr_enabled = false; } } - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; } static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) { - struct rtsx_cr_option *option = &pcr->option; rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1, CD_RESUME_EN_MASK, CD_RESUME_EN_MASK); @@ -476,17 +469,6 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); - /* - * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced - * to drive low, and we forcibly request clock. - */ - if (option->force_clkreq_0) - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); - else - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); - rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); if (pcr->rtd3_en) { diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c index 91d240dd68fa..47ab72a43256 100644 --- a/drivers/misc/cardreader/rts5249.c +++ b/drivers/misc/cardreader/rts5249.c @@ -327,12 +327,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) } } - /* * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced * to drive low, and we forcibly request clock. */ - if (option->force_clkreq_0) + if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG) rtsx_pci_write_register(pcr, PETXCFG, FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); else diff --git a/drivers/misc/cardreader/rts5260.c b/drivers/misc/cardreader/rts5260.c index 9b42b20a3e5a..79b18f6f73a8 100644 --- a/drivers/misc/cardreader/rts5260.c +++ b/drivers/misc/cardreader/rts5260.c @@ -517,17 +517,10 @@ static void rts5260_init_from_cfg(struct rtsx_pcr *pcr) option->ltr_enabled = false; } } - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; } static int rts5260_extra_init_hw(struct rtsx_pcr *pcr) { - struct rtsx_cr_option *option = &pcr->option; /* Set mcu_cnt to 7 to ensure data can be sampled properly */ rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07); @@ -546,17 +539,6 @@ static int rts5260_extra_init_hw(struct rtsx_pcr *pcr) rts5260_init_hw(pcr); - /* - * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced - * to drive low, and we forcibly request clock. - */ - if (option->force_clkreq_0) - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); - else - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00); return 0; diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c index b1e76030cafd..94af6bf8a25a 100644 --- a/drivers/misc/cardreader/rts5261.c +++ b/drivers/misc/cardreader/rts5261.c @@ -498,17 +498,10 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr) option->ltr_enabled = false; } } - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; } static int rts5261_extra_init_hw(struct rtsx_pcr *pcr) { - struct rtsx_cr_option *option = &pcr->option; u32 val; rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1, @@ -554,17 +547,6 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); - /* - * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced - * to drive low, and we forcibly request clock. - */ - if (option->force_clkreq_0) - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); - else - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); - rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); if (pcr->rtd3_en) { diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index 32b7783e9d4f..a3f4b52bb159 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -1326,8 +1326,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) return err; } - if (pcr->aspm_mode == ASPM_MODE_REG) + if (pcr->aspm_mode == ASPM_MODE_REG) { rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0x30, 0x30); + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); + } /* No CD interrupt if probing driver with card inserted. * So we need to initialize pcr->card_exist here. -- cgit v1.2.3 From 77107b08f0f29c6e9d02c2e4bfcd6e1e0c57bdd5 Mon Sep 17 00:00:00 2001 From: Esteban Blanc Date: Thu, 27 Jul 2023 11:04:35 +0200 Subject: misc: tps6594-esm: Disable ESM for rev 1 PMIC Due to a silicon bug, ESM on TPS6594 PMIC revision 1 is not working properly. This patch keeps SOC ESM disabled for such PMIC. Fixes: 875fdd0787e4 ("misc: tps6594-esm: Add driver for TI TPS6594 ESM") Co-developed-by: Julien Panis Signed-off-by: Julien Panis Signed-off-by: Esteban Blanc Link: https://lore.kernel.org/r/20230726-tps6594_fix_esm_for_v1-v1-1-2adfdcad31c2@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/tps6594-esm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/misc/tps6594-esm.c b/drivers/misc/tps6594-esm.c index b488f704f104..05e2c151e632 100644 --- a/drivers/misc/tps6594-esm.c +++ b/drivers/misc/tps6594-esm.c @@ -13,6 +13,8 @@ #include +#define TPS6594_DEV_REV_1 0x08 + static irqreturn_t tps6594_esm_isr(int irq, void *dev_id) { struct platform_device *pdev = dev_id; @@ -32,11 +34,26 @@ static int tps6594_esm_probe(struct platform_device *pdev) { struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; + unsigned int rev; int irq; int ret; int i; - for (i = 0 ; i < pdev->num_resources ; i++) { + /* + * Due to a bug in revision 1 of the PMIC, the GPIO3 used for the + * SoC ESM function is used to power the load switch instead. + * As a consequence, ESM can not be used on those PMIC. + * Check the version and return an error in case of revision 1. + */ + ret = regmap_read(tps->regmap, TPS6594_REG_DEV_REV, &rev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read PMIC revision\n"); + if (rev == TPS6594_DEV_REV_1) + return dev_err_probe(dev, -ENODEV, + "ESM not supported for revision 1 PMIC\n"); + + for (i = 0; i < pdev->num_resources; i++) { irq = platform_get_irq_byname(pdev, pdev->resource[i].name); if (irq < 0) return dev_err_probe(dev, irq, "Failed to get %s irq\n", -- cgit v1.2.3 From b3d8aa84bbfe9b58ccc5332cacf8ea17200af310 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Sat, 29 Jul 2023 18:29:02 -0700 Subject: rust: allocator: Prevent mis-aligned allocation Currently the rust allocator simply passes the size of the type Layout to krealloc(), and in theory the alignment requirement from the type Layout may be larger than the guarantee provided by SLAB, which means the allocated object is mis-aligned. Fix this by adjusting the allocation size to the nearest power of two, which SLAB always guarantees a size-aligned allocation. And because Rust guarantees that the original size must be a multiple of alignment and the alignment must be a power of two, then the alignment requirement is satisfied. Suggested-by: Vlastimil Babka Co-developed-by: "Andreas Hindborg (Samsung)" Signed-off-by: "Andreas Hindborg (Samsung)" Signed-off-by: Boqun Feng Cc: stable@vger.kernel.org # v6.1+ Acked-by: Vlastimil Babka Fixes: 247b365dc8dc ("rust: add `kernel` crate") Link: https://github.com/Rust-for-Linux/linux/issues/974 Link: https://lore.kernel.org/r/20230730012905.643822-2-boqun.feng@gmail.com [ Applied rewording of comment as discussed in the mailing list. ] Signed-off-by: Miguel Ojeda --- rust/bindings/bindings_helper.h | 1 + rust/kernel/allocator.rs | 74 ++++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 3e601ce2548d..058954961bfc 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -13,5 +13,6 @@ #include /* `bindgen` gets confused at certain things. */ +const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN; const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL; const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO; diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs index 397a3dd57a9b..9363b527be66 100644 --- a/rust/kernel/allocator.rs +++ b/rust/kernel/allocator.rs @@ -9,6 +9,36 @@ use crate::bindings; struct KernelAllocator; +/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment. +/// +/// # Safety +/// +/// - `ptr` can be either null or a pointer which has been allocated by this allocator. +/// - `new_layout` must have a non-zero size. +unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gfp_t) -> *mut u8 { + // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. + let layout = new_layout.pad_to_align(); + + let mut size = layout.size(); + + if layout.align() > bindings::BINDINGS_ARCH_SLAB_MINALIGN { + // The alignment requirement exceeds the slab guarantee, thus try to enlarge the size + // to use the "power-of-two" size/alignment guarantee (see comments in `kmalloc()` for + // more information). + // + // Note that `layout.size()` (after padding) is guaranteed to be a multiple of + // `layout.align()`, so `next_power_of_two` gives enough alignment guarantee. + size = size.next_power_of_two(); + } + + // SAFETY: + // - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the + // function safety requirement. + // - `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero + // according to the function safety requirement) or a result from `next_power_of_two()`. + unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags) as *mut u8 } +} + unsafe impl GlobalAlloc for KernelAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // `krealloc()` is used instead of `kmalloc()` because the latter is @@ -30,10 +60,20 @@ static ALLOCATOR: KernelAllocator = KernelAllocator; // to extract the object file that has them from the archive. For the moment, // let's generate them ourselves instead. // +// Note: Although these are *safe* functions, they are called by the compiler +// with parameters that obey the same `GlobalAlloc` function safety +// requirements: size and align should form a valid layout, and size is +// greater than 0. +// // Note that `#[no_mangle]` implies exported too, nowadays. #[no_mangle] -fn __rust_alloc(size: usize, _align: usize) -> *mut u8 { - unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 } +fn __rust_alloc(size: usize, align: usize) -> *mut u8 { + // SAFETY: See assumption above. + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; + + // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater + // than 0. + unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } } #[no_mangle] @@ -42,23 +82,27 @@ fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) { } #[no_mangle] -fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 { - unsafe { - bindings::krealloc( - ptr as *const core::ffi::c_void, - new_size, - bindings::GFP_KERNEL, - ) as *mut u8 - } +fn __rust_realloc(ptr: *mut u8, _old_size: usize, align: usize, new_size: usize) -> *mut u8 { + // SAFETY: See assumption above. + let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, align) }; + + // SAFETY: Per assumption above, `ptr` is allocated by `__rust_*` before, and the size of + // `new_layout` is greater than 0. + unsafe { krealloc_aligned(ptr, new_layout, bindings::GFP_KERNEL) } } #[no_mangle] -fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 { +fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + // SAFETY: See assumption above. + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; + + // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater + // than 0. unsafe { - bindings::krealloc( - core::ptr::null(), - size, + krealloc_aligned( + ptr::null_mut(), + layout, bindings::GFP_KERNEL | bindings::__GFP_ZERO, - ) as *mut u8 + ) } } -- cgit v1.2.3 From 1d24eb2d536ba27ef938a6563ac8bfb49c738cc1 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 6 Jul 2023 09:46:15 +0000 Subject: rust: delete `ForeignOwnable::borrow_mut` We discovered that the current design of `borrow_mut` is problematic. This patch removes it until a better solution can be found. Specifically, the current design gives you access to a `&mut T`, which lets you change where the `ForeignOwnable` points (e.g., with `core::mem::swap`). No upcoming user of this API intended to make that possible, making all of them unsound. Signed-off-by: Alice Ryhl Reviewed-by: Gary Guo Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Fixes: 0fc4424d24a2 ("rust: types: introduce `ForeignOwnable`") Link: https://lore.kernel.org/r/20230706094615.3080784-1-aliceryhl@google.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 3 +-- rust/kernel/types.rs | 22 ++-------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index a89843cacaad..172f563976a9 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -243,8 +243,7 @@ impl ForeignOwnable for Arc { let inner = NonNull::new(ptr as *mut ArcInner).unwrap(); // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive - // for the lifetime of the returned value. Additionally, the safety requirements of - // `ForeignOwnable::borrow_mut` ensure that no new mutable references are created. + // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 1e5380b16ed5..d479f8da8f38 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -35,34 +35,16 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] - /// for this object must have been dropped. unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; - /// Mutably borrows a foreign-owned object. - /// - /// # Safety - /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and - /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. - unsafe fn borrow_mut(ptr: *const core::ffi::c_void) -> ScopeGuard { - // SAFETY: The safety requirements ensure that `ptr` came from a previous call to - // `into_foreign`. - ScopeGuard::new_with_data(unsafe { Self::from_foreign(ptr) }, |d| { - d.into_foreign(); - }) - } - /// Converts a foreign-owned object back to a Rust-owned one. /// /// # Safety /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and - /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. + /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for + /// this object must have been dropped. unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; } -- cgit v1.2.3 From b05544884300e98512964103b33f8f87650ce887 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Tue, 11 Jul 2023 09:19:14 +0200 Subject: rust: fix bindgen build error with UBSAN_BOUNDS_STRICT With commit 2d47c6956ab3 ("ubsan: Tighten UBSAN_BOUNDS on GCC") if CONFIG_UBSAN is enabled and gcc supports -fsanitize=bounds-strict, we can trigger the following build error due to bindgen lacking support for this additional build option: BINDGEN rust/bindings/bindings_generated.rs error: unsupported argument 'bounds-strict' to option '-fsanitize=' Fix by adding -fsanitize=bounds-strict to the list of skipped gcc flags for bindgen. Fixes: 2d47c6956ab3 ("ubsan: Tighten UBSAN_BOUNDS on GCC") Signed-off-by: Andrea Righi Acked-by: Kees Cook Reviewed-by: Martin Rodriguez Reboredo Link: https://lore.kernel.org/r/20230711071914.133946-1-andrea.righi@canonical.com Signed-off-by: Miguel Ojeda --- rust/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/Makefile b/rust/Makefile index 7c9d9f11aec5..4124bfa01798 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -257,7 +257,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ -fno-partial-inlining -fplugin-arg-arm_ssp_per_task_plugin-% \ -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \ -fzero-call-used-regs=% -fno-stack-clash-protection \ - -fno-inline-functions-called-once \ + -fno-inline-functions-called-once -fsanitize=bounds-strict \ --param=% --param asan-% # Derived from `scripts/Makefile.clang`. -- cgit v1.2.3 From 045aecdfcb2e060db142d83a0f4082380c465d2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Aug 2023 19:33:21 +0100 Subject: arm64/ptrace: Don't enable SVE when setting streaming SVE Systems which implement SME without also implementing SVE are architecturally valid but were not initially supported by the kernel, unfortunately we missed one issue in the ptrace code. The SVE register setting code is shared between SVE and streaming mode SVE. When we set full SVE register state we currently enable TIF_SVE unconditionally, in the case where streaming SVE is being configured on a system that supports vanilla SVE this is not an issue since we always initialise enough state for both vector lengths but on a system which only support SME it will result in us attempting to restore the SVE vector length after having set streaming SVE registers. Fix this by making the enabling of SVE conditional on setting SVE vector state. If we set streaming SVE state and SVE was not already enabled this will result in a SVE access trap on next use of normal SVE, this will cause us to flush our register state but this is fine since the only way to trigger a SVE access trap would be to exit streaming mode which will cause the in register state to be flushed anyway. Fixes: e12310a0d30f ("arm64/sme: Implement ptrace support for streaming mode SVE registers") Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230803-arm64-fix-ptrace-ssve-no-sve-v1-1-49df214bfb3e@kernel.org Signed-off-by: Catalin Marinas --- arch/arm64/kernel/ptrace.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 740e81e9db04..5b9b4305248b 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -932,11 +932,13 @@ static int sve_set_common(struct task_struct *target, /* * Ensure target->thread.sve_state is up to date with target's * FPSIMD regs, so that a short copyin leaves trailing - * registers unmodified. Always enable SVE even if going into - * streaming mode. + * registers unmodified. Only enable SVE if we are + * configuring normal SVE, a system with streaming SVE may not + * have normal SVE. */ fpsimd_sync_to_sve(target); - set_tsk_thread_flag(target, TIF_SVE); + if (type == ARM64_VEC_SVE) + set_tsk_thread_flag(target, TIF_SVE); target->thread.fp_type = FP_STATE_SVE; BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header)); -- cgit v1.2.3 From 507ea5dd92d23fcf10e4d1a68a443c86a49753ed Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Aug 2023 19:33:22 +0100 Subject: arm64/fpsimd: Sync FPSIMD state with SVE for SME only systems Currently we guard FPSIMD/SVE state conversions with a check for the system supporting SVE but SME only systems may need to sync streaming mode SVE state so add a check for SME support too. These functions are only used by the ptrace code. Fixes: e12310a0d30f ("arm64/sme: Implement ptrace support for streaming mode SVE registers") Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230803-arm64-fix-ptrace-ssve-no-sve-v1-2-49df214bfb3e@kernel.org Signed-off-by: Catalin Marinas --- arch/arm64/kernel/fpsimd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index a61a1fd6492d..bfaa70cb040e 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -679,7 +679,7 @@ static void fpsimd_to_sve(struct task_struct *task) void *sst = task->thread.sve_state; struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state; - if (!system_supports_sve()) + if (!system_supports_sve() && !system_supports_sme()) return; vq = sve_vq_from_vl(thread_get_cur_vl(&task->thread)); @@ -705,7 +705,7 @@ static void sve_to_fpsimd(struct task_struct *task) unsigned int i; __uint128_t const *p; - if (!system_supports_sve()) + if (!system_supports_sve() && !system_supports_sme()) return; vl = thread_get_cur_vl(&task->thread); -- cgit v1.2.3 From 69af56ae56a48a2522aad906c4461c6c7c092737 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Aug 2023 19:33:23 +0100 Subject: arm64/fpsimd: Sync and zero pad FPSIMD state for streaming SVE We have a function sve_sync_from_fpsimd_zeropad() which is used by the ptrace code to update the SVE state when the user writes to the the FPSIMD register set. Currently this checks that the task has SVE enabled but this will miss updates for tasks which have streaming SVE enabled if SVE has not been enabled for the thread, also do the conversion if the task has streaming SVE enabled. Fixes: e12310a0d30f ("arm64/sme: Implement ptrace support for streaming mode SVE registers") Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230803-arm64-fix-ptrace-ssve-no-sve-v1-3-49df214bfb3e@kernel.org Signed-off-by: Catalin Marinas --- arch/arm64/kernel/fpsimd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index bfaa70cb040e..75c37b1c55aa 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -835,7 +835,8 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task) void *sst = task->thread.sve_state; struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state; - if (!test_tsk_thread_flag(task, TIF_SVE)) + if (!test_tsk_thread_flag(task, TIF_SVE) && + !thread_sm_enabled(&task->thread)) return; vq = sve_vq_from_vl(thread_get_cur_vl(&task->thread)); -- cgit v1.2.3 From d0b4f95a51038becce4bdab4789aa7ce59d4ea6e Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Wed, 26 Jul 2023 11:53:59 +0200 Subject: riscv/kexec: handle R_RISCV_CALL_PLT relocation type R_RISCV_CALL has been deprecated and replaced by R_RISCV_CALL_PLT. See Enum 18-19 in Table 3. Relocation types here: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc It was deprecated in ("Deprecated R_RISCV_CALL, prefer R_RISCV_CALL_PLT"): https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/a0dced85018d7a0ec17023c9389cbd70b1dbc1b0 Recent tools (at least GNU binutils-2.40) already use R_RISCV_CALL_PLT. Kernels built with such binutils fail kexec_load_file(2) with: kexec_image: Unknown rela relocation: 19 kexec_image: Error loading purgatory ret=-8 The binary code at the call site remains the same, so tell arch_kexec_apply_relocations_add() to handle _PLT alike. Fixes: 838b3e28488f ("RISC-V: Load purgatory in kexec_file") Signed-off-by: Torsten Duwe Signed-off-by: Petr Tesarik Cc: Li Zhengyu Cc: stable@vger.kernel.org Reviewed-by: Conor Dooley Link: https://lore.kernel.org/all/b046b164af8efd33bbdb7d4003273bdf9196a5b0.1690365011.git.petr.tesarik.ext@huawei.com/ Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/elf_kexec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index 5372b708fae2..38390d3bdcac 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -425,6 +425,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, * sym, instead of searching the whole relsec. */ case R_RISCV_PCREL_HI20: + case R_RISCV_CALL_PLT: case R_RISCV_CALL: *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | ENCODE_UJTYPE_IMM(val - addr); -- cgit v1.2.3 From 49af7a2cd5f678217b8b4f86a29411aebebf3e78 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Wed, 26 Jul 2023 11:54:01 +0200 Subject: riscv/kexec: load initrd high in available memory When initrd is loaded low, the secondary kernel fails like this: INITRD: 0xdc581000+0x00eef000 overlaps in-use memory region This initrd load address corresponds to the _end symbol, but the reservation is aligned on PMD_SIZE, as explained by a comment in setup_bootmem(). It is technically possible to align the initrd load address accordingly, leaving a hole between the end of kernel and the initrd, but it is much simpler to allocate the initrd top-down. Fixes: 838b3e28488f ("RISC-V: Load purgatory in kexec_file") Signed-off-by: Torsten Duwe Signed-off-by: Petr Tesarik Cc: stable@vger.kernel.org Reviewed-by: Conor Dooley Link: https://lore.kernel.org/all/67c8eb9eea25717c2c8208d9bfbfaa39e6e2a1c6.1690365011.git.petr.tesarik.ext@huawei.com/ Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/elf_kexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index 38390d3bdcac..c08bb5c3b385 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -281,7 +281,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, kbuf.buffer = initrd; kbuf.bufsz = kbuf.memsz = initrd_len; kbuf.buf_align = PAGE_SIZE; - kbuf.top_down = false; + kbuf.top_down = true; kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; ret = kexec_add_buffer(&kbuf); if (ret) -- cgit v1.2.3 From c3bcc65d4d2e8292c435322cbc34c318d06b8b6c Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Tue, 4 Jul 2023 14:18:37 +0200 Subject: riscv: Start of DRAM should at least be aligned on PMD size for the direct mapping So that we do not end up mapping the whole linear mapping using 4K pages, which is slow at boot time, and also very likely at runtime. So make sure we align the start of DRAM on a PMD boundary. Signed-off-by: Alexandre Ghiti Reported-by: Song Shuai Fixes: 3335068f8721 ("riscv: Use PUD/P4D/PGD pages for the linear mapping") Tested-by: Song Shuai Link: https://lore.kernel.org/r/20230704121837.248976-1-alexghiti@rivosinc.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 9ce504737d18..ad845c3aa9b2 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -214,8 +214,13 @@ static void __init setup_bootmem(void) memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); phys_ram_end = memblock_end_of_DRAM(); + + /* + * Make sure we align the start of the memory on a PMD boundary so that + * at worst, we map the linear mapping with PMD mappings. + */ if (!IS_ENABLED(CONFIG_XIP_KERNEL)) - phys_ram_base = memblock_start_of_DRAM(); + phys_ram_base = memblock_start_of_DRAM() & PMD_MASK; /* * In 64-bit, any use of __va/__pa before this point is wrong as we -- cgit v1.2.3 From 4e15a0ddc3ff40e8ea84032213976ecf774d7f77 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Aug 2023 12:42:45 -0400 Subject: KVM: SEV: snapshot the GHCB before accessing it Validation of the GHCB is susceptible to time-of-check/time-of-use vulnerabilities. To avoid them, we would like to always snapshot the fields that are read in sev_es_validate_vmgexit(), and not use the GHCB anymore after it returns. This means: - invoking sev_es_sync_from_ghcb() before any GHCB access, including before sev_es_validate_vmgexit() - snapshotting all fields including the valid bitmap and the sw_scratch field, which are currently not caching anywhere. The valid bitmap is the first thing to be copied out of the GHCB; then, further accesses will use the copy in svm->sev_es. Fixes: 291bd20d5d88 ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT") Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/sev.c | 69 +++++++++++++++++++++++++------------------------- arch/x86/kvm/svm/svm.h | 26 +++++++++++++++++++ 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 07756b7348ae..e898f0b2b0ba 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2417,15 +2417,18 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) */ memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs)); - vcpu->arch.regs[VCPU_REGS_RAX] = ghcb_get_rax_if_valid(ghcb); - vcpu->arch.regs[VCPU_REGS_RBX] = ghcb_get_rbx_if_valid(ghcb); - vcpu->arch.regs[VCPU_REGS_RCX] = ghcb_get_rcx_if_valid(ghcb); - vcpu->arch.regs[VCPU_REGS_RDX] = ghcb_get_rdx_if_valid(ghcb); - vcpu->arch.regs[VCPU_REGS_RSI] = ghcb_get_rsi_if_valid(ghcb); + BUILD_BUG_ON(sizeof(svm->sev_es.valid_bitmap) != sizeof(ghcb->save.valid_bitmap)); + memcpy(&svm->sev_es.valid_bitmap, &ghcb->save.valid_bitmap, sizeof(ghcb->save.valid_bitmap)); - svm->vmcb->save.cpl = ghcb_get_cpl_if_valid(ghcb); + vcpu->arch.regs[VCPU_REGS_RAX] = kvm_ghcb_get_rax_if_valid(svm, ghcb); + vcpu->arch.regs[VCPU_REGS_RBX] = kvm_ghcb_get_rbx_if_valid(svm, ghcb); + vcpu->arch.regs[VCPU_REGS_RCX] = kvm_ghcb_get_rcx_if_valid(svm, ghcb); + vcpu->arch.regs[VCPU_REGS_RDX] = kvm_ghcb_get_rdx_if_valid(svm, ghcb); + vcpu->arch.regs[VCPU_REGS_RSI] = kvm_ghcb_get_rsi_if_valid(svm, ghcb); - if (ghcb_xcr0_is_valid(ghcb)) { + svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm, ghcb); + + if (kvm_ghcb_xcr0_is_valid(svm)) { vcpu->arch.xcr0 = ghcb_get_xcr0(ghcb); kvm_update_cpuid_runtime(vcpu); } @@ -2436,6 +2439,7 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) control->exit_code_hi = upper_32_bits(exit_code); control->exit_info_1 = ghcb_get_sw_exit_info_1(ghcb); control->exit_info_2 = ghcb_get_sw_exit_info_2(ghcb); + svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm, ghcb); /* Clear the valid entries fields */ memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap)); @@ -2464,56 +2468,56 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) reason = GHCB_ERR_MISSING_INPUT; - if (!ghcb_sw_exit_code_is_valid(ghcb) || - !ghcb_sw_exit_info_1_is_valid(ghcb) || - !ghcb_sw_exit_info_2_is_valid(ghcb)) + if (!kvm_ghcb_sw_exit_code_is_valid(svm) || + !kvm_ghcb_sw_exit_info_1_is_valid(svm) || + !kvm_ghcb_sw_exit_info_2_is_valid(svm)) goto vmgexit_err; switch (ghcb_get_sw_exit_code(ghcb)) { case SVM_EXIT_READ_DR7: break; case SVM_EXIT_WRITE_DR7: - if (!ghcb_rax_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_RDTSC: break; case SVM_EXIT_RDPMC: - if (!ghcb_rcx_is_valid(ghcb)) + if (!kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_CPUID: - if (!ghcb_rax_is_valid(ghcb) || - !ghcb_rcx_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm) || + !kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; if (ghcb_get_rax(ghcb) == 0xd) - if (!ghcb_xcr0_is_valid(ghcb)) + if (!kvm_ghcb_xcr0_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_INVD: break; case SVM_EXIT_IOIO: if (ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_STR_MASK) { - if (!ghcb_sw_scratch_is_valid(ghcb)) + if (!kvm_ghcb_sw_scratch_is_valid(svm)) goto vmgexit_err; } else { if (!(ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_TYPE_MASK)) - if (!ghcb_rax_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm)) goto vmgexit_err; } break; case SVM_EXIT_MSR: - if (!ghcb_rcx_is_valid(ghcb)) + if (!kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; if (ghcb_get_sw_exit_info_1(ghcb)) { - if (!ghcb_rax_is_valid(ghcb) || - !ghcb_rdx_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm) || + !kvm_ghcb_rdx_is_valid(svm)) goto vmgexit_err; } break; case SVM_EXIT_VMMCALL: - if (!ghcb_rax_is_valid(ghcb) || - !ghcb_cpl_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm) || + !kvm_ghcb_cpl_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_RDTSCP: @@ -2521,19 +2525,19 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) case SVM_EXIT_WBINVD: break; case SVM_EXIT_MONITOR: - if (!ghcb_rax_is_valid(ghcb) || - !ghcb_rcx_is_valid(ghcb) || - !ghcb_rdx_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm) || + !kvm_ghcb_rcx_is_valid(svm) || + !kvm_ghcb_rdx_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_MWAIT: - if (!ghcb_rax_is_valid(ghcb) || - !ghcb_rcx_is_valid(ghcb)) + if (!kvm_ghcb_rax_is_valid(svm) || + !kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; break; case SVM_VMGEXIT_MMIO_READ: case SVM_VMGEXIT_MMIO_WRITE: - if (!ghcb_sw_scratch_is_valid(ghcb)) + if (!kvm_ghcb_sw_scratch_is_valid(svm)) goto vmgexit_err; break; case SVM_VMGEXIT_NMI_COMPLETE: @@ -2563,9 +2567,6 @@ vmgexit_err: dump_ghcb(svm); } - /* Clear the valid entries fields */ - memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap)); - ghcb_set_sw_exit_info_1(ghcb, 2); ghcb_set_sw_exit_info_2(ghcb, reason); @@ -2586,7 +2587,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm) */ if (svm->sev_es.ghcb_sa_sync) { kvm_write_guest(svm->vcpu.kvm, - ghcb_get_sw_scratch(svm->sev_es.ghcb), + svm->sev_es.sw_scratch, svm->sev_es.ghcb_sa, svm->sev_es.ghcb_sa_len); svm->sev_es.ghcb_sa_sync = false; @@ -2637,7 +2638,7 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) u64 scratch_gpa_beg, scratch_gpa_end; void *scratch_va; - scratch_gpa_beg = ghcb_get_sw_scratch(ghcb); + scratch_gpa_beg = svm->sev_es.sw_scratch; if (!scratch_gpa_beg) { pr_err("vmgexit: scratch gpa not provided\n"); goto e_scratch; @@ -2853,11 +2854,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) exit_code = ghcb_get_sw_exit_code(ghcb); + sev_es_sync_from_ghcb(svm); ret = sev_es_validate_vmgexit(svm); if (ret) return ret; - sev_es_sync_from_ghcb(svm); ghcb_set_sw_exit_info_1(ghcb, 0); ghcb_set_sw_exit_info_2(ghcb, 0); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 18af7e712a5a..8239c8de45ac 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -190,10 +190,12 @@ struct vcpu_sev_es_state { /* SEV-ES support */ struct sev_es_save_area *vmsa; struct ghcb *ghcb; + u8 valid_bitmap[16]; struct kvm_host_map ghcb_map; bool received_first_sipi; /* SEV-ES scratch area support */ + u64 sw_scratch; void *ghcb_sa; u32 ghcb_sa_len; bool ghcb_sa_sync; @@ -744,4 +746,28 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm); void __svm_sev_es_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted); void __svm_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted); +#define DEFINE_KVM_GHCB_ACCESSORS(field) \ + static __always_inline bool kvm_ghcb_##field##_is_valid(const struct vcpu_svm *svm) \ + { \ + return test_bit(GHCB_BITMAP_IDX(field), \ + (unsigned long *)&svm->sev_es.valid_bitmap); \ + } \ + \ + static __always_inline u64 kvm_ghcb_get_##field##_if_valid(struct vcpu_svm *svm, struct ghcb *ghcb) \ + { \ + return kvm_ghcb_##field##_is_valid(svm) ? ghcb->save.field : 0; \ + } \ + +DEFINE_KVM_GHCB_ACCESSORS(cpl) +DEFINE_KVM_GHCB_ACCESSORS(rax) +DEFINE_KVM_GHCB_ACCESSORS(rcx) +DEFINE_KVM_GHCB_ACCESSORS(rdx) +DEFINE_KVM_GHCB_ACCESSORS(rbx) +DEFINE_KVM_GHCB_ACCESSORS(rsi) +DEFINE_KVM_GHCB_ACCESSORS(sw_exit_code) +DEFINE_KVM_GHCB_ACCESSORS(sw_exit_info_1) +DEFINE_KVM_GHCB_ACCESSORS(sw_exit_info_2) +DEFINE_KVM_GHCB_ACCESSORS(sw_scratch) +DEFINE_KVM_GHCB_ACCESSORS(xcr0) + #endif -- cgit v1.2.3 From 7588dbcebcbf0193ab5b76987396d0254270b04a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Aug 2023 12:56:36 -0400 Subject: KVM: SEV: only access GHCB fields once A KVM guest using SEV-ES or SEV-SNP with multiple vCPUs can trigger a double fetch race condition vulnerability and invoke the VMGEXIT handler recursively. sev_handle_vmgexit() maps the GHCB page using kvm_vcpu_map() and then fetches the exit code using ghcb_get_sw_exit_code(). Soon after, sev_es_validate_vmgexit() fetches the exit code again. Since the GHCB page is shared with the guest, the guest is able to quickly swap the values with another vCPU and hence bypass the validation. One vmexit code that can be rejected by sev_es_validate_vmgexit() is SVM_EXIT_VMGEXIT; if sev_handle_vmgexit() observes it in the second fetch, the call to svm_invoke_exit_handler() will invoke sev_handle_vmgexit() again recursively. To avoid the race, always fetch the GHCB data from the places where sev_es_sync_from_ghcb stores it. Exploiting recursions on linux kernel has been proven feasible in the past, but the impact is mitigated by stack guard pages (CONFIG_VMAP_STACK). Still, if an attacker manages to call the handler multiple times, they can theoretically trigger a stack overflow and cause a denial-of-service, or potentially guest-to-host escape in kernel configurations without stack guard pages. Note that winning the race reliably in every iteration is very tricky due to the very tight window of the fetches; depending on the compiler settings, they are often consecutive because of optimization and inlining. Tested by booting an SEV-ES RHEL9 guest. Fixes: CVE-2023-4155 Fixes: 291bd20d5d88 ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT") Cc: stable@vger.kernel.org Reported-by: Andy Nguyen Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/sev.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index e898f0b2b0ba..ca4ba5fe9a01 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2445,9 +2445,15 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap)); } +static u64 kvm_ghcb_get_sw_exit_code(struct vmcb_control_area *control) +{ + return (((u64)control->exit_code_hi) << 32) | control->exit_code; +} + static int sev_es_validate_vmgexit(struct vcpu_svm *svm) { - struct kvm_vcpu *vcpu; + struct vmcb_control_area *control = &svm->vmcb->control; + struct kvm_vcpu *vcpu = &svm->vcpu; struct ghcb *ghcb; u64 exit_code; u64 reason; @@ -2458,7 +2464,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) * Retrieve the exit code now even though it may not be marked valid * as it could help with debugging. */ - exit_code = ghcb_get_sw_exit_code(ghcb); + exit_code = kvm_ghcb_get_sw_exit_code(control); /* Only GHCB Usage code 0 is supported */ if (ghcb->ghcb_usage) { @@ -2473,7 +2479,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) !kvm_ghcb_sw_exit_info_2_is_valid(svm)) goto vmgexit_err; - switch (ghcb_get_sw_exit_code(ghcb)) { + switch (exit_code) { case SVM_EXIT_READ_DR7: break; case SVM_EXIT_WRITE_DR7: @@ -2490,18 +2496,18 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) if (!kvm_ghcb_rax_is_valid(svm) || !kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; - if (ghcb_get_rax(ghcb) == 0xd) + if (vcpu->arch.regs[VCPU_REGS_RAX] == 0xd) if (!kvm_ghcb_xcr0_is_valid(svm)) goto vmgexit_err; break; case SVM_EXIT_INVD: break; case SVM_EXIT_IOIO: - if (ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_STR_MASK) { + if (control->exit_info_1 & SVM_IOIO_STR_MASK) { if (!kvm_ghcb_sw_scratch_is_valid(svm)) goto vmgexit_err; } else { - if (!(ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_TYPE_MASK)) + if (!(control->exit_info_1 & SVM_IOIO_TYPE_MASK)) if (!kvm_ghcb_rax_is_valid(svm)) goto vmgexit_err; } @@ -2509,7 +2515,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) case SVM_EXIT_MSR: if (!kvm_ghcb_rcx_is_valid(svm)) goto vmgexit_err; - if (ghcb_get_sw_exit_info_1(ghcb)) { + if (control->exit_info_1) { if (!kvm_ghcb_rax_is_valid(svm) || !kvm_ghcb_rdx_is_valid(svm)) goto vmgexit_err; @@ -2553,8 +2559,6 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) return 0; vmgexit_err: - vcpu = &svm->vcpu; - if (reason == GHCB_ERR_INVALID_USAGE) { vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n", ghcb->ghcb_usage); @@ -2852,8 +2856,6 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) trace_kvm_vmgexit_enter(vcpu->vcpu_id, ghcb); - exit_code = ghcb_get_sw_exit_code(ghcb); - sev_es_sync_from_ghcb(svm); ret = sev_es_validate_vmgexit(svm); if (ret) @@ -2862,6 +2864,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) ghcb_set_sw_exit_info_1(ghcb, 0); ghcb_set_sw_exit_info_2(ghcb, 0); + exit_code = kvm_ghcb_get_sw_exit_code(control); switch (exit_code) { case SVM_VMGEXIT_MMIO_READ: ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); -- cgit v1.2.3 From 63dbc67cf4ed11f94b2e8dde34b41438a3cb3d83 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Aug 2023 13:01:43 -0400 Subject: KVM: SEV: remove ghcb variable declarations To avoid possible time-of-check/time-of-use issues, the GHCB should almost never be accessed outside dump_ghcb, sev_es_sync_to_ghcb and sev_es_sync_from_ghcb. The only legitimate uses are to set the exitinfo fields and to find the address of the scratch area embedded in the ghcb. Accessing ghcb_usage also goes through svm->sev_es.ghcb in sev_es_validate_vmgexit(), but that is because anyway the value is not used. Removing a shortcut variable that contains the value of svm->sev_es.ghcb makes these cases a bit more verbose, but it limits the chance of someone reading the ghcb by mistake. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/sev.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index ca4ba5fe9a01..d3aec1f2cad2 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2454,12 +2454,9 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) { struct vmcb_control_area *control = &svm->vmcb->control; struct kvm_vcpu *vcpu = &svm->vcpu; - struct ghcb *ghcb; u64 exit_code; u64 reason; - ghcb = svm->sev_es.ghcb; - /* * Retrieve the exit code now even though it may not be marked valid * as it could help with debugging. @@ -2467,7 +2464,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) exit_code = kvm_ghcb_get_sw_exit_code(control); /* Only GHCB Usage code 0 is supported */ - if (ghcb->ghcb_usage) { + if (svm->sev_es.ghcb->ghcb_usage) { reason = GHCB_ERR_INVALID_USAGE; goto vmgexit_err; } @@ -2561,7 +2558,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) vmgexit_err: if (reason == GHCB_ERR_INVALID_USAGE) { vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n", - ghcb->ghcb_usage); + svm->sev_es.ghcb->ghcb_usage); } else if (reason == GHCB_ERR_INVALID_EVENT) { vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n", exit_code); @@ -2571,8 +2568,8 @@ vmgexit_err: dump_ghcb(svm); } - ghcb_set_sw_exit_info_1(ghcb, 2); - ghcb_set_sw_exit_info_2(ghcb, reason); + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, reason); /* Resume the guest to "return" the error code. */ return 1; @@ -2637,7 +2634,6 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu) static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) { struct vmcb_control_area *control = &svm->vmcb->control; - struct ghcb *ghcb = svm->sev_es.ghcb; u64 ghcb_scratch_beg, ghcb_scratch_end; u64 scratch_gpa_beg, scratch_gpa_end; void *scratch_va; @@ -2713,8 +2709,8 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len) return 0; e_scratch: - ghcb_set_sw_exit_info_1(ghcb, 2); - ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_SCRATCH_AREA); + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_SCRATCH_AREA); return 1; } @@ -2827,7 +2823,6 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); struct vmcb_control_area *control = &svm->vmcb->control; u64 ghcb_gpa, exit_code; - struct ghcb *ghcb; int ret; /* Validate the GHCB */ @@ -2852,17 +2847,16 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) } svm->sev_es.ghcb = svm->sev_es.ghcb_map.hva; - ghcb = svm->sev_es.ghcb_map.hva; - trace_kvm_vmgexit_enter(vcpu->vcpu_id, ghcb); + trace_kvm_vmgexit_enter(vcpu->vcpu_id, svm->sev_es.ghcb); sev_es_sync_from_ghcb(svm); ret = sev_es_validate_vmgexit(svm); if (ret) return ret; - ghcb_set_sw_exit_info_1(ghcb, 0); - ghcb_set_sw_exit_info_2(ghcb, 0); + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 0); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 0); exit_code = kvm_ghcb_get_sw_exit_code(control); switch (exit_code) { @@ -2902,13 +2896,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) break; case 1: /* Get AP jump table address */ - ghcb_set_sw_exit_info_2(ghcb, sev->ap_jump_table); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, sev->ap_jump_table); break; default: pr_err("svm: vmgexit: unsupported AP jump table request - exit_info_1=%#llx\n", control->exit_info_1); - ghcb_set_sw_exit_info_1(ghcb, 2); - ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_INPUT); + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT); } ret = 1; -- cgit v1.2.3 From 797964253d358cf8d705614dda394dbe30120223 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 3 Aug 2023 11:35:53 -0700 Subject: file: reinstate f_pos locking optimization for regular files In commit 20ea1e7d13c1 ("file: always lock position for FMODE_ATOMIC_POS") we ended up always taking the file pos lock, because pidfd_getfd() could get a reference to the file even when it didn't have an elevated file count due to threading of other sharing cases. But Mateusz Guzik reports that the extra locking is actually measurable, so let's re-introduce the optimization, and only force the locking for directory traversal. Directories need the lock for correctness reasons, while regular files only need it for "POSIX semantics". Since pidfd_getfd() is about debuggers etc special things that are _way_ outside of POSIX, we can relax the rules for that case. Reported-by: Mateusz Guzik Cc: Christian Brauner Link: https://lore.kernel.org/linux-fsdevel/20230803095311.ijpvhx3fyrbkasul@f/ Signed-off-by: Linus Torvalds --- fs/file.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index 35c62b54c9d6..dbca26ef7a01 100644 --- a/fs/file.c +++ b/fs/file.c @@ -1036,12 +1036,28 @@ unsigned long __fdget_raw(unsigned int fd) return __fget_light(fd, 0); } +/* + * Try to avoid f_pos locking. We only need it if the + * file is marked for FMODE_ATOMIC_POS, and it can be + * accessed multiple ways. + * + * Always do it for directories, because pidfd_getfd() + * can make a file accessible even if it otherwise would + * not be, and for directories this is a correctness + * issue, not a "POSIX requirement". + */ +static inline bool file_needs_f_pos_lock(struct file *file) +{ + return (file->f_mode & FMODE_ATOMIC_POS) && + (file_count(file) > 1 || S_ISDIR(file_inode(file)->i_mode)); +} + unsigned long __fdget_pos(unsigned int fd) { unsigned long v = __fdget(fd); struct file *file = (struct file *)(v & ~3); - if (file && (file->f_mode & FMODE_ATOMIC_POS)) { + if (file && file_needs_f_pos_lock(file)) { v |= FDPUT_POS_UNLOCK; mutex_lock(&file->f_pos_lock); } -- cgit v1.2.3 From 4b5d1e47b69426c0f7491d97d73ad0152d02d437 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Fri, 21 Jul 2023 14:37:01 +0800 Subject: zsmalloc: fix races between modifications of fullness and isolated We encountered many kernel exceptions of VM_BUG_ON(zspage->isolated == 0) in dec_zspage_isolation() and BUG_ON(!pages[1]) in zs_unmap_object() lately. This issue only occurs when migration and reclamation occur at the same time. With our memory stress test, we can reproduce this issue several times a day. We have no idea why no one else encountered this issue. BTW, we switched to the new kernel version with this defect a few months ago. Since fullness and isolated share the same unsigned int, modifications of them should be protected by the same lock. [andrew.yang@mediatek.com: move comment] Link: https://lkml.kernel.org/r/20230727062910.6337-1-andrew.yang@mediatek.com Link: https://lkml.kernel.org/r/20230721063705.11455-1-andrew.yang@mediatek.com Fixes: c4549b871102 ("zsmalloc: remove zspage isolation for migration") Signed-off-by: Andrew Yang Reviewed-by: Sergey Senozhatsky Cc: AngeloGioacchino Del Regno Cc: Matthias Brugger Cc: Minchan Kim Cc: Sebastian Andrzej Siewior Cc: Signed-off-by: Andrew Morton --- mm/zsmalloc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 3f057970504e..32916d28d9d9 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1798,6 +1798,7 @@ static void replace_sub_page(struct size_class *class, struct zspage *zspage, static bool zs_page_isolate(struct page *page, isolate_mode_t mode) { + struct zs_pool *pool; struct zspage *zspage; /* @@ -1807,9 +1808,10 @@ static bool zs_page_isolate(struct page *page, isolate_mode_t mode) VM_BUG_ON_PAGE(PageIsolated(page), page); zspage = get_zspage(page); - migrate_write_lock(zspage); + pool = zspage->pool; + spin_lock(&pool->lock); inc_zspage_isolation(zspage); - migrate_write_unlock(zspage); + spin_unlock(&pool->lock); return true; } @@ -1875,12 +1877,12 @@ static int zs_page_migrate(struct page *newpage, struct page *page, kunmap_atomic(s_addr); replace_sub_page(class, zspage, newpage, page); + dec_zspage_isolation(zspage); /* * Since we complete the data copy and set up new zspage structure, * it's okay to release the pool's lock. */ spin_unlock(&pool->lock); - dec_zspage_isolation(zspage); migrate_write_unlock(zspage); get_page(newpage); @@ -1897,14 +1899,16 @@ static int zs_page_migrate(struct page *newpage, struct page *page, static void zs_page_putback(struct page *page) { + struct zs_pool *pool; struct zspage *zspage; VM_BUG_ON_PAGE(!PageIsolated(page), page); zspage = get_zspage(page); - migrate_write_lock(zspage); + pool = zspage->pool; + spin_lock(&pool->lock); dec_zspage_isolation(zspage); - migrate_write_unlock(zspage); + spin_unlock(&pool->lock); } static const struct movable_operations zsmalloc_mops = { -- cgit v1.2.3 From f443fd5af5dbd531f880d3645d5dd36976cf087f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 26 Jul 2023 11:57:56 +0100 Subject: crypto, cifs: fix error handling in extract_iter_to_sg() Fix error handling in extract_iter_to_sg(). Pages need to be unpinned, not put in extract_user_to_sg() when handling IOVEC/UBUF sources. The bug may result in a warning like the following: WARNING: CPU: 1 PID: 20384 at mm/gup.c:229 __lse_atomic_add arch/arm64/include/asm/atomic_lse.h:27 [inline] WARNING: CPU: 1 PID: 20384 at mm/gup.c:229 arch_atomic_add arch/arm64/include/asm/atomic.h:28 [inline] WARNING: CPU: 1 PID: 20384 at mm/gup.c:229 raw_atomic_add include/linux/atomic/atomic-arch-fallback.h:537 [inline] WARNING: CPU: 1 PID: 20384 at mm/gup.c:229 atomic_add include/linux/atomic/atomic-instrumented.h:105 [inline] WARNING: CPU: 1 PID: 20384 at mm/gup.c:229 try_grab_page+0x108/0x160 mm/gup.c:252 ... pc : try_grab_page+0x108/0x160 mm/gup.c:229 lr : follow_page_pte+0x174/0x3e4 mm/gup.c:651 ... Call trace: __lse_atomic_add arch/arm64/include/asm/atomic_lse.h:27 [inline] arch_atomic_add arch/arm64/include/asm/atomic.h:28 [inline] raw_atomic_add include/linux/atomic/atomic-arch-fallback.h:537 [inline] atomic_add include/linux/atomic/atomic-instrumented.h:105 [inline] try_grab_page+0x108/0x160 mm/gup.c:252 follow_pmd_mask mm/gup.c:734 [inline] follow_pud_mask mm/gup.c:765 [inline] follow_p4d_mask mm/gup.c:782 [inline] follow_page_mask+0x12c/0x2e4 mm/gup.c:839 __get_user_pages+0x174/0x30c mm/gup.c:1217 __get_user_pages_locked mm/gup.c:1448 [inline] __gup_longterm_locked+0x94/0x8f4 mm/gup.c:2142 internal_get_user_pages_fast+0x970/0xb60 mm/gup.c:3140 pin_user_pages_fast+0x4c/0x60 mm/gup.c:3246 iov_iter_extract_user_pages lib/iov_iter.c:1768 [inline] iov_iter_extract_pages+0xc8/0x54c lib/iov_iter.c:1831 extract_user_to_sg lib/scatterlist.c:1123 [inline] extract_iter_to_sg lib/scatterlist.c:1349 [inline] extract_iter_to_sg+0x26c/0x6fc lib/scatterlist.c:1339 hash_sendmsg+0xc0/0x43c crypto/algif_hash.c:117 sock_sendmsg_nosec net/socket.c:725 [inline] sock_sendmsg+0x54/0x60 net/socket.c:748 ____sys_sendmsg+0x270/0x2ac net/socket.c:2494 ___sys_sendmsg+0x80/0xdc net/socket.c:2548 __sys_sendmsg+0x68/0xc4 net/socket.c:2577 __do_sys_sendmsg net/socket.c:2586 [inline] __se_sys_sendmsg net/socket.c:2584 [inline] __arm64_sys_sendmsg+0x24/0x30 net/socket.c:2584 __invoke_syscall arch/arm64/kernel/syscall.c:38 [inline] invoke_syscall+0x48/0x114 arch/arm64/kernel/syscall.c:52 el0_svc_common.constprop.0+0x44/0xe4 arch/arm64/kernel/syscall.c:142 do_el0_svc+0x38/0xa4 arch/arm64/kernel/syscall.c:191 el0_svc+0x2c/0xb0 arch/arm64/kernel/entry-common.c:647 el0t_64_sync_handler+0xc0/0xc4 arch/arm64/kernel/entry-common.c:665 el0t_64_sync+0x19c/0x1a0 arch/arm64/kernel/entry.S:591 Link: https://lkml.kernel.org/r/20571.1690369076@warthog.procyon.org.uk Fixes: 018584697533 ("netfs: Add a function to extract an iterator into a scatterlist") Reported-by: syzbot+9b82859567f2e50c123e@syzkaller.appspotmail.com Link: https://lore.kernel.org/linux-mm/000000000000273d0105ff97bf56@google.com/ Signed-off-by: David Howells Reviewed-by: David Hildenbrand Acked-by: Steve French Cc: Sven Schnelle Cc: Herbert Xu Cc: Jeff Layton Cc: Shyam Prasad N Cc: Rohith Surabattula Cc: Jens Axboe Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Matthew Wilcox Cc: Signed-off-by: Andrew Morton --- lib/scatterlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scatterlist.c b/lib/scatterlist.c index e86231a44c3d..c65566b4dc66 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -1148,7 +1148,7 @@ static ssize_t extract_user_to_sg(struct iov_iter *iter, failed: while (sgtable->nents > sgtable->orig_nents) - put_page(sg_page(&sgtable->sgl[--sgtable->nents])); + unpin_user_page(sg_page(&sgtable->sgl[--sgtable->nents])); return res; } -- cgit v1.2.3 From cac7ea57a06016e4914848b707477fb07ee4ae1c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Jul 2023 17:09:30 +0100 Subject: radix tree test suite: fix incorrect allocation size for pthreads Currently the pthread allocation for each array item is based on the size of a pthread_t pointer and should be the size of the pthread_t structure, so the allocation is under-allocating the correct size. Fix this by using the size of each element in the pthreads array. Static analysis cppcheck reported: tools/testing/radix-tree/regression1.c:180:2: warning: Size of pointer 'threads' used instead of size of its data. [pointerSize] Link: https://lkml.kernel.org/r/20230727160930.632674-1-colin.i.king@gmail.com Fixes: 1366c37ed84b ("radix tree test harness") Signed-off-by: Colin Ian King Cc: Konstantin Khlebnikov Cc: Matthew Wilcox (Oracle) Cc: Signed-off-by: Andrew Morton --- tools/testing/radix-tree/regression1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/radix-tree/regression1.c b/tools/testing/radix-tree/regression1.c index a61c7bcbc72d..63f468bf8245 100644 --- a/tools/testing/radix-tree/regression1.c +++ b/tools/testing/radix-tree/regression1.c @@ -177,7 +177,7 @@ void regression1_test(void) nr_threads = 2; pthread_barrier_init(&worker_barrier, NULL, nr_threads); - threads = malloc(nr_threads * sizeof(pthread_t *)); + threads = malloc(nr_threads * sizeof(*threads)); for (i = 0; i < nr_threads; i++) { arg = i; -- cgit v1.2.3 From f985fc322063c73916a0d5b6b3fcc6db2ba5792c Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 27 Jul 2023 19:56:40 +0800 Subject: mm/swapfile: fix wrong swap entry type for hwpoisoned swapcache page Patch series "A few fixup patches for mm", v2. This series contains a few fixup patches to fix potential unexpected return value, fix wrong swap entry type for hwpoisoned swapcache page and so on. More details can be found in the respective changelogs. This patch (of 3): Hwpoisoned dirty swap cache page is kept in the swap cache and there's simple interception code in do_swap_page() to catch it. But when trying to swapoff, unuse_pte() will wrongly install a general sense of "future accesses are invalid" swap entry for hwpoisoned swap cache page due to unaware of such type of page. The user will receive SIGBUS signal without expected BUS_MCEERR_AR payload. BTW, typo 'hwposioned' is fixed. Link: https://lkml.kernel.org/r/20230727115643.639741-1-linmiaohe@huawei.com Link: https://lkml.kernel.org/r/20230727115643.639741-2-linmiaohe@huawei.com Fixes: 6b970599e807 ("mm: hwpoison: support recovery from ksm_might_need_to_copy()") Signed-off-by: Miaohe Lin Cc: Kefeng Wang Cc: Matthew Wilcox (Oracle) Cc: Naoya Horiguchi Cc: Signed-off-by: Andrew Morton --- mm/ksm.c | 2 ++ mm/swapfile.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mm/ksm.c b/mm/ksm.c index ba266359da55..d20d7662419b 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2784,6 +2784,8 @@ struct page *ksm_might_need_to_copy(struct page *page, anon_vma->root == vma->anon_vma->root) { return page; /* still no need to copy it */ } + if (PageHWPoison(page)) + return ERR_PTR(-EHWPOISON); if (!PageUptodate(page)) return page; /* let do_swap_page report the error */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 8e6dde68b389..b15112b1f1a8 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1746,7 +1746,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, struct page *swapcache; spinlock_t *ptl; pte_t *pte, new_pte, old_pte; - bool hwposioned = false; + bool hwpoisoned = PageHWPoison(page); int ret = 1; swapcache = page; @@ -1754,7 +1754,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, if (unlikely(!page)) return -ENOMEM; else if (unlikely(PTR_ERR(page) == -EHWPOISON)) - hwposioned = true; + hwpoisoned = true; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); if (unlikely(!pte || !pte_same_as_swp(ptep_get(pte), @@ -1765,11 +1765,11 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, old_pte = ptep_get(pte); - if (unlikely(hwposioned || !PageUptodate(page))) { + if (unlikely(hwpoisoned || !PageUptodate(page))) { swp_entry_t swp_entry; dec_mm_counter(vma->vm_mm, MM_SWAPENTS); - if (hwposioned) { + if (hwpoisoned) { swp_entry = make_hwpoison_entry(swapcache); page = swapcache; } else { -- cgit v1.2.3 From f29623e4a599c295cc8f518c8e4bb7848581a14d Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 27 Jul 2023 19:56:41 +0800 Subject: mm: memory-failure: fix potential unexpected return value from unpoison_memory() If unpoison_memory() fails to clear page hwpoisoned flag, return value ret is expected to be -EBUSY. But when get_hwpoison_page() returns 1 and fails to clear page hwpoisoned flag due to races, return value will be unexpected 1 leading to users being confused. And there's a code smell that the variable "ret" is used not only to save the return value of unpoison_memory(), but also the return value from get_hwpoison_page(). Make a further cleanup by using another auto-variable solely to save the return value of get_hwpoison_page() as suggested by Naoya. Link: https://lkml.kernel.org/r/20230727115643.639741-3-linmiaohe@huawei.com Fixes: bf181c582588 ("mm/hwpoison: fix unpoison_memory()") Signed-off-by: Miaohe Lin Cc: Kefeng Wang Cc: Matthew Wilcox (Oracle) Cc: Naoya Horiguchi Cc: Signed-off-by: Andrew Morton --- mm/memory-failure.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index ece5d481b5ff..b32d370b5d43 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -2466,7 +2466,7 @@ int unpoison_memory(unsigned long pfn) { struct folio *folio; struct page *p; - int ret = -EBUSY; + int ret = -EBUSY, ghp; unsigned long count = 1; bool huge = false; static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL, @@ -2514,29 +2514,28 @@ int unpoison_memory(unsigned long pfn) if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio)) goto unlock_mutex; - ret = get_hwpoison_page(p, MF_UNPOISON); - if (!ret) { + ghp = get_hwpoison_page(p, MF_UNPOISON); + if (!ghp) { if (PageHuge(p)) { huge = true; count = folio_free_raw_hwp(folio, false); - if (count == 0) { - ret = -EBUSY; + if (count == 0) goto unlock_mutex; - } } ret = folio_test_clear_hwpoison(folio) ? 0 : -EBUSY; - } else if (ret < 0) { - if (ret == -EHWPOISON) { + } else if (ghp < 0) { + if (ghp == -EHWPOISON) { ret = put_page_back_buddy(p) ? 0 : -EBUSY; - } else + } else { + ret = ghp; unpoison_pr_info("Unpoison: failed to grab page %#lx\n", pfn, &unpoison_rs); + } } else { if (PageHuge(p)) { huge = true; count = folio_free_raw_hwp(folio, false); if (count == 0) { - ret = -EBUSY; folio_put(folio); goto unlock_mutex; } -- cgit v1.2.3 From faeb2ff2c1c5cb60ce0da193580b256c941f99ca Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 27 Jul 2023 19:56:42 +0800 Subject: mm: memory-failure: avoid false hwpoison page mapped error info folio->_mapcount is overloaded in SLAB, so folio_mapped() has to be done after folio_test_slab() is checked. Otherwise slab folio might be treated as a mapped folio leading to false 'Someone maps the hwpoison page' error info. Link: https://lkml.kernel.org/r/20230727115643.639741-4-linmiaohe@huawei.com Fixes: 230ac719c500 ("mm/hwpoison: don't try to unpoison containment-failed pages") Signed-off-by: Miaohe Lin Reviewed-by: Matthew Wilcox (Oracle) Acked-by: Naoya Horiguchi Cc: Kefeng Wang Cc: Signed-off-by: Andrew Morton --- mm/memory-failure.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index b32d370b5d43..9a285038d765 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -2499,6 +2499,13 @@ int unpoison_memory(unsigned long pfn) goto unlock_mutex; } + if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio)) + goto unlock_mutex; + + /* + * Note that folio->_mapcount is overloaded in SLAB, so the simple test + * in folio_mapped() has to be done after folio_test_slab() is checked. + */ if (folio_mapped(folio)) { unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n", pfn, &unpoison_rs); @@ -2511,9 +2518,6 @@ int unpoison_memory(unsigned long pfn) goto unlock_mutex; } - if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio)) - goto unlock_mutex; - ghp = get_hwpoison_page(p, MF_UNPOISON); if (!ghp) { if (PageHuge(p)) { -- cgit v1.2.3 From 32c877191e022b55fe3a374f3d7e9fb5741c514d Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 11 Jul 2023 15:09:41 -0700 Subject: hugetlb: do not clear hugetlb dtor until allocating vmemmap Patch series "Fix hugetlb free path race with memory errors". In the discussion of Jiaqi Yan's series "Improve hugetlbfs read on HWPOISON hugepages" the race window was discovered. https://lore.kernel.org/linux-mm/20230616233447.GB7371@monkey/ Freeing a hugetlb page back to low level memory allocators is performed in two steps. 1) Under hugetlb lock, remove page from hugetlb lists and clear destructor 2) Outside lock, allocate vmemmap if necessary and call low level free Between these two steps, the hugetlb page will appear as a normal compound page. However, vmemmap for tail pages could be missing. If a memory error occurs at this time, we could try to update page flags non-existant page structs. A much more detailed description is in the first patch. The first patch addresses the race window. However, it adds a hugetlb_lock lock/unlock cycle to every vmemmap optimized hugetlb page free operation. This could lead to slowdowns if one is freeing a large number of hugetlb pages. The second path optimizes the update_and_free_pages_bulk routine to only take the lock once in bulk operations. The second patch is technically not a bug fix, but includes a Fixes tag and Cc stable to avoid a performance regression. It can be combined with the first, but was done separately make reviewing easier. This patch (of 2): Freeing a hugetlb page and releasing base pages back to the underlying allocator such as buddy or cma is performed in two steps: - remove_hugetlb_folio() is called to remove the folio from hugetlb lists, get a ref on the page and remove hugetlb destructor. This all must be done under the hugetlb lock. After this call, the page can be treated as a normal compound page or a collection of base size pages. - update_and_free_hugetlb_folio() is called to allocate vmemmap if needed and the free routine of the underlying allocator is called on the resulting page. We can not hold the hugetlb lock here. One issue with this scheme is that a memory error could occur between these two steps. In this case, the memory error handling code treats the old hugetlb page as a normal compound page or collection of base pages. It will then try to SetPageHWPoison(page) on the page with an error. If the page with error is a tail page without vmemmap, a write error will occur when trying to set the flag. Address this issue by modifying remove_hugetlb_folio() and update_and_free_hugetlb_folio() such that the hugetlb destructor is not cleared until after allocating vmemmap. Since clearing the destructor requires holding the hugetlb lock, the clearing is done in remove_hugetlb_folio() if the vmemmap is present. This saves a lock/unlock cycle. Otherwise, destructor is cleared in update_and_free_hugetlb_folio() after allocating vmemmap. Note that this will leave hugetlb pages in a state where they are marked free (by hugetlb specific page flag) and have a ref count. This is not a normal state. The only code that would notice is the memory error code, and it is set up to retry in such a case. A subsequent patch will create a routine to do bulk processing of vmemmap allocation. This will eliminate a lock/unlock cycle for each hugetlb page in the case where we are freeing a large number of pages. Link: https://lkml.kernel.org/r/20230711220942.43706-1-mike.kravetz@oracle.com Link: https://lkml.kernel.org/r/20230711220942.43706-2-mike.kravetz@oracle.com Fixes: ad2fa3717b74 ("mm: hugetlb: alloc the vmemmap pages associated with each HugeTLB page") Signed-off-by: Mike Kravetz Reviewed-by: Muchun Song Tested-by: Naoya Horiguchi Cc: Axel Rasmussen Cc: James Houghton Cc: Jiaqi Yan Cc: Miaohe Lin Cc: Michal Hocko Cc: Signed-off-by: Andrew Morton --- mm/hugetlb.c | 75 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 64a3239b6407..6da626bfb52e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1579,9 +1579,37 @@ static inline void destroy_compound_gigantic_folio(struct folio *folio, unsigned int order) { } #endif +static inline void __clear_hugetlb_destructor(struct hstate *h, + struct folio *folio) +{ + lockdep_assert_held(&hugetlb_lock); + + /* + * Very subtle + * + * For non-gigantic pages set the destructor to the normal compound + * page dtor. This is needed in case someone takes an additional + * temporary ref to the page, and freeing is delayed until they drop + * their reference. + * + * For gigantic pages set the destructor to the null dtor. This + * destructor will never be called. Before freeing the gigantic + * page destroy_compound_gigantic_folio will turn the folio into a + * simple group of pages. After this the destructor does not + * apply. + * + */ + if (hstate_is_gigantic(h)) + folio_set_compound_dtor(folio, NULL_COMPOUND_DTOR); + else + folio_set_compound_dtor(folio, COMPOUND_PAGE_DTOR); +} + /* - * Remove hugetlb folio from lists, and update dtor so that the folio appears - * as just a compound page. + * Remove hugetlb folio from lists. + * If vmemmap exists for the folio, update dtor so that the folio appears + * as just a compound page. Otherwise, wait until after allocating vmemmap + * to update dtor. * * A reference is held on the folio, except in the case of demote. * @@ -1612,31 +1640,19 @@ static void __remove_hugetlb_folio(struct hstate *h, struct folio *folio, } /* - * Very subtle - * - * For non-gigantic pages set the destructor to the normal compound - * page dtor. This is needed in case someone takes an additional - * temporary ref to the page, and freeing is delayed until they drop - * their reference. - * - * For gigantic pages set the destructor to the null dtor. This - * destructor will never be called. Before freeing the gigantic - * page destroy_compound_gigantic_folio will turn the folio into a - * simple group of pages. After this the destructor does not - * apply. - * - * This handles the case where more than one ref is held when and - * after update_and_free_hugetlb_folio is called. - * - * In the case of demote we do not ref count the page as it will soon - * be turned into a page of smaller size. + * We can only clear the hugetlb destructor after allocating vmemmap + * pages. Otherwise, someone (memory error handling) may try to write + * to tail struct pages. + */ + if (!folio_test_hugetlb_vmemmap_optimized(folio)) + __clear_hugetlb_destructor(h, folio); + + /* + * In the case of demote we do not ref count the page as it will soon + * be turned into a page of smaller size. */ if (!demote) folio_ref_unfreeze(folio, 1); - if (hstate_is_gigantic(h)) - folio_set_compound_dtor(folio, NULL_COMPOUND_DTOR); - else - folio_set_compound_dtor(folio, COMPOUND_PAGE_DTOR); h->nr_huge_pages--; h->nr_huge_pages_node[nid]--; @@ -1705,6 +1721,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h, { int i; struct page *subpage; + bool clear_dtor = folio_test_hugetlb_vmemmap_optimized(folio); if (hstate_is_gigantic(h) && !gigantic_page_runtime_supported()) return; @@ -1735,6 +1752,16 @@ static void __update_and_free_hugetlb_folio(struct hstate *h, if (unlikely(folio_test_hwpoison(folio))) folio_clear_hugetlb_hwpoison(folio); + /* + * If vmemmap pages were allocated above, then we need to clear the + * hugetlb destructor under the hugetlb lock. + */ + if (clear_dtor) { + spin_lock_irq(&hugetlb_lock); + __clear_hugetlb_destructor(h, folio); + spin_unlock_irq(&hugetlb_lock); + } + for (i = 0; i < pages_per_huge_page(h); i++) { subpage = folio_page(folio, i); subpage->flags &= ~(1 << PG_locked | 1 << PG_error | -- cgit v1.2.3 From 65294de30cb8bc7659e445f7be2846af9ed35499 Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Fri, 28 Jul 2023 22:09:51 +0530 Subject: selftests: mm: ksm: fix incorrect evaluation of parameter A missing break in kms_tests leads to kselftest hang when the parameter -s is used. In current code flow because of missing break in -s, -t parses args spilled from -s and as -t accepts only valid values as 0,1 so any arg in -s >1 or <0, gets in ksm_test failure This went undetected since, before the addition of option -t, the next case -M would immediately break out of the switch statement but that is no longer the case Add the missing break statement. ----Before---- ./ksm_tests -H -s 100 Invalid merge type ----After---- ./ksm_tests -H -s 100 Number of normal pages: 0 Number of huge pages: 50 Total size: 100 MiB Total time: 0.401732682 s Average speed: 248.922 MiB/s Link: https://lkml.kernel.org/r/20230728163952.4634-1-ayush.jain3@amd.com Fixes: 07115fcc15b4 ("selftests/mm: add new selftests for KSM") Signed-off-by: Ayush Jain Reviewed-by: David Hildenbrand Cc: Stefan Roesch Cc: Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/ksm_tests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c index 435acebdc325..380b691d3eb9 100644 --- a/tools/testing/selftests/mm/ksm_tests.c +++ b/tools/testing/selftests/mm/ksm_tests.c @@ -831,6 +831,7 @@ int main(int argc, char *argv[]) printf("Size must be greater than 0\n"); return KSFT_FAIL; } + break; case 't': { int tmp = atoi(optarg); -- cgit v1.2.3 From 493614da0d4e8d8bb37c3c558e0c01de20344cff Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Mon, 31 Jul 2023 13:24:50 -0400 Subject: mm: compaction: fix endless looping over same migrate block During stress testing, the following situation was observed: 70 root 39 19 0 0 0 R 100.0 0.0 959:29.92 khugepaged 310936 root 20 0 84416 25620 512 R 99.7 1.5 642:37.22 hugealloc Tracing shows isolate_migratepages_block() endlessly looping over the first block in the DMA zone: hugealloc-310936 [001] ..... 237297.415718: mm_compaction_finished: node=0 zone=DMA order=9 ret=no_suitable_page hugealloc-310936 [001] ..... 237297.415718: mm_compaction_isolate_migratepages: range=(0x1 ~ 0x400) nr_scanned=513 nr_taken=0 hugealloc-310936 [001] ..... 237297.415718: mm_compaction_finished: node=0 zone=DMA order=9 ret=no_suitable_page hugealloc-310936 [001] ..... 237297.415718: mm_compaction_isolate_migratepages: range=(0x1 ~ 0x400) nr_scanned=513 nr_taken=0 hugealloc-310936 [001] ..... 237297.415718: mm_compaction_finished: node=0 zone=DMA order=9 ret=no_suitable_page hugealloc-310936 [001] ..... 237297.415718: mm_compaction_isolate_migratepages: range=(0x1 ~ 0x400) nr_scanned=513 nr_taken=0 hugealloc-310936 [001] ..... 237297.415718: mm_compaction_finished: node=0 zone=DMA order=9 ret=no_suitable_page hugealloc-310936 [001] ..... 237297.415718: mm_compaction_isolate_migratepages: range=(0x1 ~ 0x400) nr_scanned=513 nr_taken=0 The problem is that the functions tries to test and set the skip bit once on the block, to avoid skipping on its own skip-set, using pageblock_aligned() on the pfn as a test. But because this is the DMA zone which starts at pfn 1, this is never true for the first block, and the skip bit isn't set or tested at all. As a result, fast_find_migrateblock() returns the same pageblock over and over. If the pfn isn't pageblock-aligned, also check if it's the start of the zone to ensure test-and-set-exactly-once on unaligned ranges. Thanks to Vlastimil Babka for the help in debugging this. Link: https://lkml.kernel.org/r/20230731172450.1632195-1-hannes@cmpxchg.org Fixes: 90ed667c03fe ("Revert "Revert "mm/compaction: fix set skip in fast_find_migrateblock""") Signed-off-by: Johannes Weiner Reviewed-by: Vlastimil Babka Acked-by: Mel Gorman Reviewed-by: Baolin Wang Signed-off-by: Andrew Morton --- mm/compaction.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index dbc9f86b1934..eacca2794e47 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -912,11 +912,12 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, /* * Check if the pageblock has already been marked skipped. - * Only the aligned PFN is checked as the caller isolates + * Only the first PFN is checked as the caller isolates * COMPACT_CLUSTER_MAX at a time so the second call must * not falsely conclude that the block should be skipped. */ - if (!valid_page && pageblock_aligned(low_pfn)) { + if (!valid_page && (pageblock_aligned(low_pfn) || + low_pfn == cc->zone->zone_start_pfn)) { if (!isolation_suitable(cc, page)) { low_pfn = end_pfn; folio = NULL; @@ -2002,7 +2003,8 @@ static isolate_migrate_t isolate_migratepages(struct compact_control *cc) * before making it "skip" so other compaction instances do * not scan the same block. */ - if (pageblock_aligned(low_pfn) && + if ((pageblock_aligned(low_pfn) || + low_pfn == cc->zone->zone_start_pfn) && !fast_find_block && !isolation_suitable(cc, page)) continue; -- cgit v1.2.3 From d1ef9dba07bf637995202d0efd29c2fea19e809c Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Mon, 31 Jul 2023 13:55:42 -0400 Subject: MAINTAINERS: add maple tree mailing list There is a mailing list for the maple tree development. Add the list to the maple tree entry of the MAINTAINERS file so patches will be sent to interested parties. Link: https://lkml.kernel.org/r/20230731175542.1653200-1-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett Signed-off-by: Andrew Morton --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 53b7ca804465..8355ec45452b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12481,6 +12481,7 @@ F: net/mctp/ MAPLE TREE M: Liam R. Howlett +L: maple-tree@lists.infradead.org L: linux-mm@kvack.org S: Supported F: Documentation/core-api/maple_tree.rst -- cgit v1.2.3 From 17457784004c84178798432a029ab20e14f728b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 31 Jul 2023 22:50:21 +0100 Subject: fs/proc/kcore: reinstate bounce buffer for KCORE_TEXT regions Some architectures do not populate the entire range categorised by KCORE_TEXT, so we must ensure that the kernel address we read from is valid. Unfortunately there is no solution currently available to do so with a purely iterator solution so reinstate the bounce buffer in this instance so we can use copy_from_kernel_nofault() in order to avoid page faults when regions are unmapped. This change partly reverts commit 2e1c0170771e ("fs/proc/kcore: avoid bounce buffer for ktext data"), reinstating the bounce buffer, but adapts the code to continue to use an iterator. [lstoakes@gmail.com: correct comment to be strictly correct about reasoning] Link: https://lkml.kernel.org/r/525a3f14-74fa-4c22-9fca-9dab4de8a0c3@lucifer.local Link: https://lkml.kernel.org/r/20230731215021.70911-1-lstoakes@gmail.com Fixes: 2e1c0170771e ("fs/proc/kcore: avoid bounce buffer for ktext data") Signed-off-by: Lorenzo Stoakes Reported-by: Jiri Olsa Closes: https://lore.kernel.org/all/ZHc2fm+9daF6cgCE@krava Tested-by: Jiri Olsa Tested-by: Will Deacon Cc: Alexander Viro Cc: Ard Biesheuvel Cc: Baoquan He Cc: Catalin Marinas Cc: David Hildenbrand Cc: Jens Axboe Cc: Kefeng Wang Cc: Liu Shixin Cc: Matthew Wilcox Cc: Mike Galbraith Cc: Thorsten Leemhuis Cc: Uladzislau Rezki (Sony) Cc: Signed-off-by: Andrew Morton --- fs/proc/kcore.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 9cb32e1a78a0..23fc24d16b31 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -309,6 +309,8 @@ static void append_kcore_note(char *notes, size_t *i, const char *name, static ssize_t read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter) { + struct file *file = iocb->ki_filp; + char *buf = file->private_data; loff_t *fpos = &iocb->ki_pos; size_t phdrs_offset, notes_offset, data_offset; size_t page_offline_frozen = 1; @@ -555,10 +557,21 @@ static ssize_t read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter) case KCORE_VMEMMAP: case KCORE_TEXT: /* - * We use _copy_to_iter() to bypass usermode hardening - * which would otherwise prevent this operation. + * Sadly we must use a bounce buffer here to be able to + * make use of copy_from_kernel_nofault(), as these + * memory regions might not always be mapped on all + * architectures. */ - if (_copy_to_iter((char *)start, tsz, iter) != tsz) { + if (copy_from_kernel_nofault(buf, (void *)start, tsz)) { + if (iov_iter_zero(tsz, iter) != tsz) { + ret = -EFAULT; + goto out; + } + /* + * We know the bounce buffer is safe to copy from, so + * use _copy_to_iter() directly. + */ + } else if (_copy_to_iter(buf, tsz, iter) != tsz) { ret = -EFAULT; goto out; } @@ -595,6 +608,10 @@ static int open_kcore(struct inode *inode, struct file *filp) if (ret) return ret; + filp->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + if (kcore_need_update) kcore_update_ram(); if (i_size_read(inode) != proc_root_kcore->size) { @@ -605,9 +622,16 @@ static int open_kcore(struct inode *inode, struct file *filp) return 0; } +static int release_kcore(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + static const struct proc_ops kcore_proc_ops = { .proc_read_iter = read_kcore_iter, .proc_open = open_kcore, + .proc_release = release_kcore, .proc_lseek = default_llseek, }; -- cgit v1.2.3 From fac2650276eced3c94bcdbc21d0e5be637c1e582 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Tue, 1 Aug 2023 09:56:32 -0400 Subject: selftests: cgroup: fix test_kmem_basic false positives This test fails routinely in our prod testing environment, and I can reproduce it locally as well. The test allocates dcache inside a cgroup, then drops the memory limit and checks that usage drops correspondingly. The reason it fails is because dentries are freed with an RCU delay - a debugging sleep shows that usage drops as expected shortly after. Insert a 1s sleep after dropping the limit. This should be good enough, assuming that machines running those tests are otherwise not very busy. Link: https://lkml.kernel.org/r/20230801135632.1768830-1-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Paul E. McKenney Cc: Michal Hocko Cc: Roman Gushchin Signed-off-by: Andrew Morton --- tools/testing/selftests/cgroup/test_kmem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/cgroup/test_kmem.c b/tools/testing/selftests/cgroup/test_kmem.c index 258ddc565deb..1b2cec9d18a4 100644 --- a/tools/testing/selftests/cgroup/test_kmem.c +++ b/tools/testing/selftests/cgroup/test_kmem.c @@ -70,6 +70,10 @@ static int test_kmem_basic(const char *root) goto cleanup; cg_write(cg, "memory.high", "1M"); + + /* wait for RCU freeing */ + sleep(1); + slab1 = cg_read_key_long(cg, "memory.stat", "slab "); if (slab1 <= 0) goto cleanup; -- cgit v1.2.3 From f8654743a0e6909dc634cbfad6db6816f10f3399 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 29 Jul 2023 04:13:18 +0900 Subject: nilfs2: fix use-after-free of nilfs_root in dirtying inodes via iput During unmount process of nilfs2, nothing holds nilfs_root structure after nilfs2 detaches its writer in nilfs_detach_log_writer(). Previously, nilfs_evict_inode() could cause use-after-free read for nilfs_root if inodes are left in "garbage_list" and released by nilfs_dispose_list at the end of nilfs_detach_log_writer(), and this bug was fixed by commit 9b5a04ac3ad9 ("nilfs2: fix use-after-free bug of nilfs_root in nilfs_evict_inode()"). However, it turned out that there is another possibility of UAF in the call path where mark_inode_dirty_sync() is called from iput(): nilfs_detach_log_writer() nilfs_dispose_list() iput() mark_inode_dirty_sync() __mark_inode_dirty() nilfs_dirty_inode() __nilfs_mark_inode_dirty() nilfs_load_inode_block() --> causes UAF of nilfs_root struct This can happen after commit 0ae45f63d4ef ("vfs: add support for a lazytime mount option"), which changed iput() to call mark_inode_dirty_sync() on its final reference if i_state has I_DIRTY_TIME flag and i_nlink is non-zero. This issue appears after commit 28a65b49eb53 ("nilfs2: do not write dirty data after degenerating to read-only") when using the syzbot reproducer, but the issue has potentially existed before. Fix this issue by adding a "purging flag" to the nilfs structure, setting that flag while disposing the "garbage_list" and checking it in __nilfs_mark_inode_dirty(). Unlike commit 9b5a04ac3ad9 ("nilfs2: fix use-after-free bug of nilfs_root in nilfs_evict_inode()"), this patch does not rely on ns_writer to determine whether to skip operations, so as not to break recovery on mount. The nilfs_salvage_orphan_logs routine dirties the buffer of salvaged data before attaching the log writer, so changing __nilfs_mark_inode_dirty() to skip the operation when ns_writer is NULL will cause recovery write to fail. The purpose of using the cleanup-only flag is to allow for narrowing of such conditions. Link: https://lkml.kernel.org/r/20230728191318.33047-1-konishi.ryusuke@gmail.com Signed-off-by: Ryusuke Konishi Reported-by: syzbot+74db8b3087f293d3a13a@syzkaller.appspotmail.com Closes: https://lkml.kernel.org/r/000000000000b4e906060113fd63@google.com Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option") Tested-by: Ryusuke Konishi Cc: # 4.0+ Signed-off-by: Andrew Morton --- fs/nilfs2/inode.c | 8 ++++++++ fs/nilfs2/segment.c | 2 ++ fs/nilfs2/the_nilfs.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index a8ce522ac747..35bc79305318 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -1101,9 +1101,17 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned int nr_dirty) int __nilfs_mark_inode_dirty(struct inode *inode, int flags) { + struct the_nilfs *nilfs = inode->i_sb->s_fs_info; struct buffer_head *ibh; int err; + /* + * Do not dirty inodes after the log writer has been detached + * and its nilfs_root struct has been freed. + */ + if (unlikely(nilfs_purging(nilfs))) + return 0; + err = nilfs_load_inode_block(inode, &ibh); if (unlikely(err)) { nilfs_warn(inode->i_sb, diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index c2553024bd25..581691e4be49 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2845,6 +2845,7 @@ void nilfs_detach_log_writer(struct super_block *sb) nilfs_segctor_destroy(nilfs->ns_writer); nilfs->ns_writer = NULL; } + set_nilfs_purging(nilfs); /* Force to free the list of dirty files */ spin_lock(&nilfs->ns_inode_lock); @@ -2857,4 +2858,5 @@ void nilfs_detach_log_writer(struct super_block *sb) up_write(&nilfs->ns_segctor_sem); nilfs_dispose_list(nilfs, &garbage_list, 1); + clear_nilfs_purging(nilfs); } diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 47c7dfbb7ea5..cd4ae1b8ae16 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -29,6 +29,7 @@ enum { THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ THE_NILFS_GC_RUNNING, /* gc process is running */ THE_NILFS_SB_DIRTY, /* super block is dirty */ + THE_NILFS_PURGING, /* disposing dirty files for cleanup */ }; /** @@ -208,6 +209,7 @@ THE_NILFS_FNS(INIT, init) THE_NILFS_FNS(DISCONTINUED, discontinued) THE_NILFS_FNS(GC_RUNNING, gc_running) THE_NILFS_FNS(SB_DIRTY, sb_dirty) +THE_NILFS_FNS(PURGING, purging) /* * Mount option operations -- cgit v1.2.3 From 5f1fc67f2cb8d3035d3acd273b48b97835af8afd Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 29 Jul 2023 20:37:32 +0000 Subject: mm/damon/core: initialize damo_filter->list from damos_new_filter() damos_new_filter() is not initializing the list field of newly allocated filter object. However, DAMON sysfs interface and DAMON_RECLAIM are not initializing it after calling damos_new_filter(). As a result, accessing uninitialized memory is possible. Actually, adding multiple DAMOS filters via DAMON sysfs interface caused NULL pointer dereferencing. Initialize the field just after the allocation from damos_new_filter(). Link: https://lkml.kernel.org/r/20230729203733.38949-2-sj@kernel.org Fixes: 98def236f63c ("mm/damon/core: implement damos filter") Signed-off-by: SeongJae Park Cc: Signed-off-by: Andrew Morton --- mm/damon/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/damon/core.c b/mm/damon/core.c index 91cff7f2997e..eb9580942a5c 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -273,6 +273,7 @@ struct damos_filter *damos_new_filter(enum damos_filter_type type, return NULL; filter->type = type; filter->matching = matching; + INIT_LIST_HEAD(&filter->list); return filter; } -- cgit v1.2.3 From 3bfc37d92687b4b19056998cebc02f94fbc81427 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 4 Aug 2023 11:54:43 -0500 Subject: Revert "PCI: mvebu: Mark driver as BROKEN" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit b3574f579ece ("PCI: mvebu: Mark driver as BROKEN") made it impossible to enable the pci-mvebu driver. The driver does have known problems, but as Russell and Uwe reported, it does work in some configurations, so removing it broke some working setups. Revert b3574f579ece so pci-mvebu is available. Reported-by: Russell King (Oracle) Link: https://lore.kernel.org/r/ZMzicVQEyHyZzBOc@shell.armlinux.org.uk Reported-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230804134622.pmbymxtzxj2yfhri@pengutronix.de Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 8d49bad7f847..0859be86e718 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -179,7 +179,6 @@ config PCI_MVEBU depends on MVEBU_MBUS depends on ARM depends on OF - depends on BROKEN select PCI_BRIDGE_EMUL help Add support for Marvell EBU PCIe controller. This PCIe controller -- cgit v1.2.3 From d5ad9aae13dcced333c1a7816ff0a4fbbb052466 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Aug 2023 20:22:11 +0100 Subject: selftests/rseq: Fix build with undefined __weak Commit 3bcbc20942db ("selftests/rseq: Play nice with binaries statically linked against glibc 2.35+") which is now in Linus' tree introduced uses of __weak but did nothing to ensure that a definition is provided for it resulting in build failures for the rseq tests: rseq.c:41:1: error: unknown type name '__weak' __weak ptrdiff_t __rseq_offset; ^ rseq.c:41:17: error: expected ';' after top level declarator __weak ptrdiff_t __rseq_offset; ^ ; rseq.c:42:1: error: unknown type name '__weak' __weak unsigned int __rseq_size; ^ rseq.c:43:1: error: unknown type name '__weak' __weak unsigned int __rseq_flags; Fix this by using the definition from tools/include compiler.h. Fixes: 3bcbc20942db ("selftests/rseq: Play nice with binaries statically linked against glibc 2.35+") Signed-off-by: Mark Brown Message-Id: <20230804-kselftest-rseq-build-v1-1-015830b66aa9@kernel.org> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/rseq/Makefile | 4 +++- tools/testing/selftests/rseq/rseq.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile index b357ba24af06..7a957c7d459a 100644 --- a/tools/testing/selftests/rseq/Makefile +++ b/tools/testing/selftests/rseq/Makefile @@ -4,8 +4,10 @@ ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),) CLANG_FLAGS += -no-integrated-as endif +top_srcdir = ../../../.. + CFLAGS += -O2 -Wall -g -I./ $(KHDR_INCLUDES) -L$(OUTPUT) -Wl,-rpath=./ \ - $(CLANG_FLAGS) + $(CLANG_FLAGS) -I$(top_srcdir)/tools/include LDLIBS += -lpthread -ldl # Own dependencies because we only want to build against 1st prerequisite, but diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/rseq/rseq.c index a723da253244..96e812bdf8a4 100644 --- a/tools/testing/selftests/rseq/rseq.c +++ b/tools/testing/selftests/rseq/rseq.c @@ -31,6 +31,8 @@ #include #include +#include + #include "../kselftest.h" #include "rseq.h" -- cgit v1.2.3 From 17ebf8a4c38b5481c29623f5e003fdf7583947f9 Mon Sep 17 00:00:00 2001 From: Xiang Yang Date: Thu, 3 Aug 2023 07:24:38 +0000 Subject: mptcp: fix the incorrect judgment for msk->cb_flags Coccicheck reports the error below: net/mptcp/protocol.c:3330:15-28: ERROR: test of a variable/field address Since the address of msk->cb_flags is used in __test_and_clear_bit, the address should not be NULL. The judgment for if (unlikely(msk->cb_flags)) will always be true, we should check the real value of msk->cb_flags here. Fixes: 65a569b03ca8 ("mptcp: optimize release_cb for the common case") Signed-off-by: Xiang Yang Reviewed-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230803072438.1847500-1-xiangyang3@huawei.com Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 3317d1cca156..be5f6f4b94c7 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3328,7 +3328,7 @@ static void mptcp_release_cb(struct sock *sk) if (__test_and_clear_bit(MPTCP_CLEAN_UNA, &msk->cb_flags)) __mptcp_clean_una_wakeup(sk); - if (unlikely(&msk->cb_flags)) { + if (unlikely(msk->cb_flags)) { /* be sure to set the current sk state before tacking actions * depending on sk_state, that is processing MPTCP_ERROR_REPORT */ -- cgit v1.2.3 From a94c16a2fda010866b8858a386a8bfbeba4f72c5 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 3 Aug 2023 16:42:53 +0300 Subject: net: dsa: ocelot: call dsa_tag_8021q_unregister() under rtnl_lock() on driver remove When the tagging protocol in current use is "ocelot-8021q" and we unbind the driver, we see this splat: $ echo '0000:00:00.2' > /sys/bus/pci/drivers/fsl_enetc/unbind mscc_felix 0000:00:00.5 swp0: left promiscuous mode sja1105 spi2.0: Link is Down DSA: tree 1 torn down mscc_felix 0000:00:00.5 swp2: left promiscuous mode sja1105 spi2.2: Link is Down DSA: tree 3 torn down fsl_enetc 0000:00:00.2 eno2: left promiscuous mode mscc_felix 0000:00:00.5: Link is Down ------------[ cut here ]------------ RTNL: assertion failed at net/dsa/tag_8021q.c (409) WARNING: CPU: 1 PID: 329 at net/dsa/tag_8021q.c:409 dsa_tag_8021q_unregister+0x12c/0x1a0 Modules linked in: CPU: 1 PID: 329 Comm: bash Not tainted 6.5.0-rc3+ #771 pc : dsa_tag_8021q_unregister+0x12c/0x1a0 lr : dsa_tag_8021q_unregister+0x12c/0x1a0 Call trace: dsa_tag_8021q_unregister+0x12c/0x1a0 felix_tag_8021q_teardown+0x130/0x150 felix_teardown+0x3c/0xd8 dsa_tree_teardown_switches+0xbc/0xe0 dsa_unregister_switch+0x168/0x260 felix_pci_remove+0x30/0x60 pci_device_remove+0x4c/0x100 device_release_driver_internal+0x188/0x288 device_links_unbind_consumers+0xfc/0x138 device_release_driver_internal+0xe0/0x288 device_driver_detach+0x24/0x38 unbind_store+0xd8/0x108 drv_attr_store+0x30/0x50 ---[ end trace 0000000000000000 ]--- ------------[ cut here ]------------ RTNL: assertion failed at net/8021q/vlan_core.c (376) WARNING: CPU: 1 PID: 329 at net/8021q/vlan_core.c:376 vlan_vid_del+0x1b8/0x1f0 CPU: 1 PID: 329 Comm: bash Tainted: G W 6.5.0-rc3+ #771 pc : vlan_vid_del+0x1b8/0x1f0 lr : vlan_vid_del+0x1b8/0x1f0 dsa_tag_8021q_unregister+0x8c/0x1a0 felix_tag_8021q_teardown+0x130/0x150 felix_teardown+0x3c/0xd8 dsa_tree_teardown_switches+0xbc/0xe0 dsa_unregister_switch+0x168/0x260 felix_pci_remove+0x30/0x60 pci_device_remove+0x4c/0x100 device_release_driver_internal+0x188/0x288 device_links_unbind_consumers+0xfc/0x138 device_release_driver_internal+0xe0/0x288 device_driver_detach+0x24/0x38 unbind_store+0xd8/0x108 drv_attr_store+0x30/0x50 DSA: tree 0 torn down This was somewhat not so easy to spot, because "ocelot-8021q" is not the default tagging protocol, and thus, not everyone who tests the unbinding path may have switched to it beforehand. The default felix_tag_npi_teardown() does not require rtnl_lock() to be held. Fixes: 7c83a7c539ab ("net: dsa: add a second tagger for Ocelot switches based on tag_8021q") Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20230803134253.2711124-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 8da46d284e35..bef879c6d500 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1625,8 +1625,10 @@ static void felix_teardown(struct dsa_switch *ds) struct felix *felix = ocelot_to_felix(ocelot); struct dsa_port *dp; + rtnl_lock(); if (felix->tag_proto_ops) felix->tag_proto_ops->teardown(ds); + rtnl_unlock(); dsa_switch_for_each_available_port(dp, ds) ocelot_deinit_port(ocelot, dp->index); -- cgit v1.2.3 From 8a9896177784063d01068293caea3f74f6830ff6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Aug 2023 14:56:00 +0000 Subject: net/packet: annotate data-races around tp->status Another syzbot report [1] is about tp->status lockless reads from __packet_get_status() [1] BUG: KCSAN: data-race in __packet_rcv_has_room / __packet_set_status write to 0xffff888117d7c080 of 8 bytes by interrupt on cpu 0: __packet_set_status+0x78/0xa0 net/packet/af_packet.c:407 tpacket_rcv+0x18bb/0x1a60 net/packet/af_packet.c:2483 deliver_skb net/core/dev.c:2173 [inline] __netif_receive_skb_core+0x408/0x1e80 net/core/dev.c:5337 __netif_receive_skb_one_core net/core/dev.c:5491 [inline] __netif_receive_skb+0x57/0x1b0 net/core/dev.c:5607 process_backlog+0x21f/0x380 net/core/dev.c:5935 __napi_poll+0x60/0x3b0 net/core/dev.c:6498 napi_poll net/core/dev.c:6565 [inline] net_rx_action+0x32b/0x750 net/core/dev.c:6698 __do_softirq+0xc1/0x265 kernel/softirq.c:571 invoke_softirq kernel/softirq.c:445 [inline] __irq_exit_rcu+0x57/0xa0 kernel/softirq.c:650 sysvec_apic_timer_interrupt+0x6d/0x80 arch/x86/kernel/apic/apic.c:1106 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:645 smpboot_thread_fn+0x33c/0x4a0 kernel/smpboot.c:112 kthread+0x1d7/0x210 kernel/kthread.c:379 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:308 read to 0xffff888117d7c080 of 8 bytes by interrupt on cpu 1: __packet_get_status net/packet/af_packet.c:436 [inline] packet_lookup_frame net/packet/af_packet.c:524 [inline] __tpacket_has_room net/packet/af_packet.c:1255 [inline] __packet_rcv_has_room+0x3f9/0x450 net/packet/af_packet.c:1298 tpacket_rcv+0x275/0x1a60 net/packet/af_packet.c:2285 deliver_skb net/core/dev.c:2173 [inline] dev_queue_xmit_nit+0x38a/0x5e0 net/core/dev.c:2243 xmit_one net/core/dev.c:3574 [inline] dev_hard_start_xmit+0xcf/0x3f0 net/core/dev.c:3594 __dev_queue_xmit+0xefb/0x1d10 net/core/dev.c:4244 dev_queue_xmit include/linux/netdevice.h:3088 [inline] can_send+0x4eb/0x5d0 net/can/af_can.c:276 bcm_can_tx+0x314/0x410 net/can/bcm.c:302 bcm_tx_timeout_handler+0xdb/0x260 __run_hrtimer kernel/time/hrtimer.c:1685 [inline] __hrtimer_run_queues+0x217/0x700 kernel/time/hrtimer.c:1749 hrtimer_run_softirq+0xd6/0x120 kernel/time/hrtimer.c:1766 __do_softirq+0xc1/0x265 kernel/softirq.c:571 run_ksoftirqd+0x17/0x20 kernel/softirq.c:939 smpboot_thread_fn+0x30a/0x4a0 kernel/smpboot.c:164 kthread+0x1d7/0x210 kernel/kthread.c:379 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:308 value changed: 0x0000000000000000 -> 0x0000000020000081 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 19 Comm: ksoftirqd/1 Not tainted 6.4.0-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 Fixes: 69e3c75f4d54 ("net: TX_RING and packet mmap") Reported-by: syzbot Signed-off-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20230803145600.2937518-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/packet/af_packet.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a4631cb457a9..a2935bd18ed9 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -401,18 +401,20 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status) { union tpacket_uhdr h; + /* WRITE_ONCE() are paired with READ_ONCE() in __packet_get_status */ + h.raw = frame; switch (po->tp_version) { case TPACKET_V1: - h.h1->tp_status = status; + WRITE_ONCE(h.h1->tp_status, status); flush_dcache_page(pgv_to_page(&h.h1->tp_status)); break; case TPACKET_V2: - h.h2->tp_status = status; + WRITE_ONCE(h.h2->tp_status, status); flush_dcache_page(pgv_to_page(&h.h2->tp_status)); break; case TPACKET_V3: - h.h3->tp_status = status; + WRITE_ONCE(h.h3->tp_status, status); flush_dcache_page(pgv_to_page(&h.h3->tp_status)); break; default: @@ -429,17 +431,19 @@ static int __packet_get_status(const struct packet_sock *po, void *frame) smp_rmb(); + /* READ_ONCE() are paired with WRITE_ONCE() in __packet_set_status */ + h.raw = frame; switch (po->tp_version) { case TPACKET_V1: flush_dcache_page(pgv_to_page(&h.h1->tp_status)); - return h.h1->tp_status; + return READ_ONCE(h.h1->tp_status); case TPACKET_V2: flush_dcache_page(pgv_to_page(&h.h2->tp_status)); - return h.h2->tp_status; + return READ_ONCE(h.h2->tp_status); case TPACKET_V3: flush_dcache_page(pgv_to_page(&h.h3->tp_status)); - return h.h3->tp_status; + return READ_ONCE(h.h3->tp_status); default: WARN(1, "TPACKET version not supported.\n"); BUG(); -- cgit v1.2.3 From 6a7ac3d20593865209dceb554d8b3f094c6bd940 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 3 Aug 2023 17:26:49 +0200 Subject: tunnels: fix kasan splat when generating ipv4 pmtu error If we try to emit an icmp error in response to a nonliner skb, we get BUG: KASAN: slab-out-of-bounds in ip_compute_csum+0x134/0x220 Read of size 4 at addr ffff88811c50db00 by task iperf3/1691 CPU: 2 PID: 1691 Comm: iperf3 Not tainted 6.5.0-rc3+ #309 [..] kasan_report+0x105/0x140 ip_compute_csum+0x134/0x220 iptunnel_pmtud_build_icmp+0x554/0x1020 skb_tunnel_check_pmtu+0x513/0xb80 vxlan_xmit_one+0x139e/0x2ef0 vxlan_xmit+0x1867/0x2760 dev_hard_start_xmit+0x1ee/0x4f0 br_dev_queue_push_xmit+0x4d1/0x660 [..] ip_compute_csum() cannot deal with nonlinear skbs, so avoid it. After this change, splat is gone and iperf3 is no longer stuck. Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets") Signed-off-by: Florian Westphal Link: https://lore.kernel.org/r/20230803152653.29535-2-fw@strlen.de Signed-off-by: Jakub Kicinski --- net/ipv4/ip_tunnel_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 92c02c886fe7..586b1b3e35b8 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -224,7 +224,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu) .un.frag.__unused = 0, .un.frag.mtu = htons(mtu), }; - icmph->checksum = ip_compute_csum(icmph, len); + icmph->checksum = csum_fold(skb_checksum(skb, 0, len, 0)); skb_reset_transport_header(skb); niph = skb_push(skb, sizeof(*niph)); -- cgit v1.2.3 From 136a1b434bbb90c5e50831646ad0680c744c79bb Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 3 Aug 2023 17:26:50 +0200 Subject: selftests: net: test vxlan pmtu exceptions with tcp TCP might get stuck if a nonlinear skb exceeds the path MTU, icmp error contains an incorrect icmp checksum in that case. Extend the existing test for vxlan to also send at least 1MB worth of data via TCP in addition to the existing 'large icmp packet adds route exception'. On my test VM this fails due to 0-size output file without "tunnels: fix kasan splat when generating ipv4 pmtu error". Signed-off-by: Florian Westphal Link: https://lore.kernel.org/r/20230803152653.29535-3-fw@strlen.de Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/pmtu.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index dfe3d287f01d..f838dd370f6a 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -361,6 +361,7 @@ err_buf= tcpdump_pids= nettest_pids= socat_pids= +tmpoutfile= err() { err_buf="${err_buf}${1} @@ -951,6 +952,7 @@ cleanup() { ip link del veth_A-R1 2>/dev/null ovs-vsctl --if-exists del-port vxlan_a 2>/dev/null ovs-vsctl --if-exists del-br ovs_br0 2>/dev/null + rm -f "$tmpoutfile" } mtu() { @@ -1328,6 +1330,39 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() { check_pmtu_value ${exp_mtu} "${pmtu}" "exceeding link layer MTU on bridged ${type} interface" pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst})" check_pmtu_value ${exp_mtu} "${pmtu}" "exceeding link layer MTU on locally bridged ${type} interface" + + tmpoutfile=$(mktemp) + + # Flush Exceptions, retry with TCP + run_cmd ${ns_a} ip route flush cached ${dst} + run_cmd ${ns_b} ip route flush cached ${dst} + run_cmd ${ns_c} ip route flush cached ${dst} + + for target in "${ns_a}" "${ns_c}" ; do + if [ ${family} -eq 4 ]; then + TCPDST=TCP:${dst}:50000 + else + TCPDST="TCP:[${dst}]:50000" + fi + ${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000 STDOUT > $tmpoutfile & + + sleep 1 + + dd if=/dev/zero of=/dev/stdout status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3 + + size=$(du -sb $tmpoutfile) + size=${size%%/tmp/*} + + [ $size -ne 1048576 ] && err "File size $size mismatches exepcted value in locally bridged vxlan test" && return 1 + done + + rm -f "$tmpoutfile" + + # Check that exceptions were created + pmtu="$(route_get_dst_pmtu_from_exception "${ns_c}" ${dst})" + check_pmtu_value ${exp_mtu} "${pmtu}" "tcp: exceeding link layer MTU on bridged ${type} interface" + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst})" + check_pmtu_value ${exp_mtu} "${pmtu}" "tcp exceeding link layer MTU on locally bridged ${type} interface" } test_pmtu_ipv4_br_vxlan4_exception() { -- cgit v1.2.3 From aaf2123a5cf46dbd97f84b6eee80269758064d93 Mon Sep 17 00:00:00 2001 From: Andrea Claudi Date: Thu, 3 Aug 2023 18:27:27 +0200 Subject: selftests: mptcp: join: fix 'delete and re-add' test mptcp_join 'delete and re-add' test fails when using ip mptcp: $ ./mptcp_join.sh -iI 002 delete and re-add before delete[ ok ] mptcp_info subflows=1 [ ok ] Error: argument "ADDRESS" is wrong: invalid for non-zero id address after delete[fail] got 2:2 subflows expected 1 This happens because endpoint delete includes an ip address while id is not 0, contrary to what is indicated in the ip mptcp man page: "When used with the delete id operation, an IFADDR is only included when the ID is 0." This fixes the issue using the $addr variable in pm_nl_del_endpoint() only when id is 0. Fixes: 34aa6e3bccd8 ("selftests: mptcp: add ip mptcp wrappers") Cc: stable@vger.kernel.org Signed-off-by: Andrea Claudi Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230803-upstream-net-20230803-misc-fixes-6-5-v1-1-6671b1ab11cc@tessares.net Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 3c2096ac97ef..067fabc401f1 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -705,6 +705,7 @@ pm_nl_del_endpoint() local addr=$3 if [ $ip_mptcp -eq 1 ]; then + [ $id -ne 0 ] && addr='' ip -n $ns mptcp endpoint delete id $id $addr else ip netns exec $ns ./pm_nl_ctl del $id $addr -- cgit v1.2.3 From c8c101ae390a3e817369e94a6f12a1ddea420702 Mon Sep 17 00:00:00 2001 From: Andrea Claudi Date: Thu, 3 Aug 2023 18:27:28 +0200 Subject: selftests: mptcp: join: fix 'implicit EP' test mptcp_join 'implicit EP' test currently fails when using ip mptcp: $ ./mptcp_join.sh -iI 001 implicit EP creation[fail] expected '10.0.2.2 10.0.2.2 id 1 implicit' found '10.0.2.2 id 1 rawflags 10 ' Error: too many addresses or duplicate one: -22. ID change is prevented[fail] expected '10.0.2.2 10.0.2.2 id 1 implicit' found '10.0.2.2 id 1 rawflags 10 ' modif is allowed[fail] expected '10.0.2.2 10.0.2.2 id 1 signal' found '10.0.2.2 id 1 signal ' This happens because of two reasons: - iproute v6.3.0 does not support the implicit flag, fixed with iproute2-next commit 3a2535a41854 ("mptcp: add support for implicit flag") - pm_nl_check_endpoint wrongly expects the ip address to be repeated two times in iproute output, and does not account for a final whitespace in it. This fixes the issue trimming the whitespace in the output string and removing the double address in the expected string. Fixes: 69c6ce7b6eca ("selftests: mptcp: add implicit endpoint test case") Cc: stable@vger.kernel.org Signed-off-by: Andrea Claudi Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230803-upstream-net-20230803-misc-fixes-6-5-v1-2-6671b1ab11cc@tessares.net Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 067fabc401f1..d01b73a8ed0f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -796,10 +796,11 @@ pm_nl_check_endpoint() fi if [ $ip_mptcp -eq 1 ]; then + # get line and trim trailing whitespace line=$(ip -n $ns mptcp endpoint show $id) + line="${line% }" # the dump order is: address id flags port dev - expected_line="$addr" - [ -n "$addr" ] && expected_line="$expected_line $addr" + [ -n "$addr" ] && expected_line="$addr" expected_line="$expected_line $id" [ -n "$_flags" ] && expected_line="$expected_line ${_flags//","/" "}" [ -n "$dev" ] && expected_line="$expected_line $dev" -- cgit v1.2.3 From ff18f9ef30ee87740f741b964375d0cfb84e1ec2 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 3 Aug 2023 18:27:29 +0200 Subject: mptcp: avoid bogus reset on fallback close Since the blamed commit, the MPTCP protocol unconditionally sends TCP resets on all the subflows on disconnect(). That fits full-blown MPTCP sockets - to implement the fastclose mechanism - but causes unexpected corruption of the data stream, caught as sporadic self-tests failures. Fixes: d21f83485518 ("mptcp: use fastclose on more edge scenarios") Cc: stable@vger.kernel.org Tested-by: Matthieu Baerts Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/419 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230803-upstream-net-20230803-misc-fixes-6-5-v1-3-6671b1ab11cc@tessares.net Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index be5f6f4b94c7..d80658547836 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2335,7 +2335,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); - if (flags & MPTCP_CF_FASTCLOSE) { + if ((flags & MPTCP_CF_FASTCLOSE) && !__mptcp_check_fallback(msk)) { /* be sure to force the tcp_disconnect() path, * to generate the egress reset */ -- cgit v1.2.3 From 511b90e39250135a7f900f1c3afbce25543018a2 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 3 Aug 2023 18:27:30 +0200 Subject: mptcp: fix disconnect vs accept race Despite commit 0ad529d9fd2b ("mptcp: fix possible divide by zero in recvmsg()"), the mptcp protocol is still prone to a race between disconnect() (or shutdown) and accept. The root cause is that the mentioned commit checks the msk-level flag, but mptcp_stream_accept() does acquire the msk-level lock, as it can rely directly on the first subflow lock. As reported by Christoph than can lead to a race where an msk socket is accepted after that mptcp_subflow_queue_clean() releases the listener socket lock and just before it takes destructive actions leading to the following splat: BUG: kernel NULL pointer dereference, address: 0000000000000012 PGD 5a4ca067 P4D 5a4ca067 PUD 37d4c067 PMD 0 Oops: 0000 [#1] PREEMPT SMP CPU: 2 PID: 10955 Comm: syz-executor.5 Not tainted 6.5.0-rc1-gdc7b257ee5dd #37 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-2.el7 04/01/2014 RIP: 0010:mptcp_stream_accept+0x1ee/0x2f0 include/net/inet_sock.h:330 Code: 0a 09 00 48 8b 1b 4c 39 e3 74 07 e8 bc 7c 7f fe eb a1 e8 b5 7c 7f fe 4c 8b 6c 24 08 eb 05 e8 a9 7c 7f fe 49 8b 85 d8 09 00 00 <0f> b6 40 12 88 44 24 07 0f b6 6c 24 07 bf 07 00 00 00 89 ee e8 89 RSP: 0018:ffffc90000d07dc0 EFLAGS: 00010293 RAX: 0000000000000000 RBX: ffff888037e8d020 RCX: ffff88803b093300 RDX: 0000000000000000 RSI: ffffffff833822c5 RDI: ffffffff8333896a RBP: 0000607f82031520 R08: ffff88803b093300 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000003e83 R12: ffff888037e8d020 R13: ffff888037e8c680 R14: ffff888009af7900 R15: ffff888009af6880 FS: 00007fc26d708640(0000) GS:ffff88807dd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000012 CR3: 0000000066bc5001 CR4: 0000000000370ee0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: do_accept+0x1ae/0x260 net/socket.c:1872 __sys_accept4+0x9b/0x110 net/socket.c:1913 __do_sys_accept4 net/socket.c:1954 [inline] __se_sys_accept4 net/socket.c:1951 [inline] __x64_sys_accept4+0x20/0x30 net/socket.c:1951 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x47/0xa0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 Address the issue by temporary removing the pending request socket from the accept queue, so that racing accept() can't touch them. After depleting the msk - the ssk still exists, as plain TCP sockets, re-insert them into the accept queue, so that later inet_csk_listen_stop() will complete the tcp socket disposal. Fixes: 2a6a870e44dd ("mptcp: stops worker on unaccepted sockets at listener close") Cc: stable@vger.kernel.org Reported-by: Christoph Paasch Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/423 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230803-upstream-net-20230803-misc-fixes-6-5-v1-4-6671b1ab11cc@tessares.net Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.h | 1 - net/mptcp/subflow.c | 58 ++++++++++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 37fbe22e2433..ba2a873a4d2e 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -325,7 +325,6 @@ struct mptcp_sock { u32 subflow_id; u32 setsockopt_seq; char ca_name[TCP_CA_NAME_MAX]; - struct mptcp_sock *dl_next; }; #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock) diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 9ee3b7abbaf6..94ae7dd01c65 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1793,16 +1793,31 @@ static void subflow_state_change(struct sock *sk) void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_ssk) { struct request_sock_queue *queue = &inet_csk(listener_ssk)->icsk_accept_queue; - struct mptcp_sock *msk, *next, *head = NULL; - struct request_sock *req; - struct sock *sk; + struct request_sock *req, *head, *tail; + struct mptcp_subflow_context *subflow; + struct sock *sk, *ssk; - /* build a list of all unaccepted mptcp sockets */ + /* Due to lock dependencies no relevant lock can be acquired under rskq_lock. + * Splice the req list, so that accept() can not reach the pending ssk after + * the listener socket is released below. + */ spin_lock_bh(&queue->rskq_lock); - for (req = queue->rskq_accept_head; req; req = req->dl_next) { - struct mptcp_subflow_context *subflow; - struct sock *ssk = req->sk; + head = queue->rskq_accept_head; + tail = queue->rskq_accept_tail; + queue->rskq_accept_head = NULL; + queue->rskq_accept_tail = NULL; + spin_unlock_bh(&queue->rskq_lock); + + if (!head) + return; + /* can't acquire the msk socket lock under the subflow one, + * or will cause ABBA deadlock + */ + release_sock(listener_ssk); + + for (req = head; req; req = req->dl_next) { + ssk = req->sk; if (!sk_is_mptcp(ssk)) continue; @@ -1810,32 +1825,10 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s if (!subflow || !subflow->conn) continue; - /* skip if already in list */ sk = subflow->conn; - msk = mptcp_sk(sk); - if (msk->dl_next || msk == head) - continue; - sock_hold(sk); - msk->dl_next = head; - head = msk; - } - spin_unlock_bh(&queue->rskq_lock); - if (!head) - return; - - /* can't acquire the msk socket lock under the subflow one, - * or will cause ABBA deadlock - */ - release_sock(listener_ssk); - - for (msk = head; msk; msk = next) { - sk = (struct sock *)msk; lock_sock_nested(sk, SINGLE_DEPTH_NESTING); - next = msk->dl_next; - msk->dl_next = NULL; - __mptcp_unaccepted_force_close(sk); release_sock(sk); @@ -1859,6 +1852,13 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s /* we are still under the listener msk socket lock */ lock_sock_nested(listener_ssk, SINGLE_DEPTH_NESTING); + + /* restore the listener queue, to let the TCP code clean it up */ + spin_lock_bh(&queue->rskq_lock); + WARN_ON_ONCE(queue->rskq_accept_head); + queue->rskq_accept_head = head; + queue->rskq_accept_tail = tail; + spin_unlock_bh(&queue->rskq_lock); } static int subflow_ulp_init(struct sock *sk) -- cgit v1.2.3 From a47e598fbd8617967e49d85c49c22f9fc642704c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Aug 2023 16:30:21 +0000 Subject: dccp: fix data-race around dp->dccps_mss_cache dccp_sendmsg() reads dp->dccps_mss_cache before locking the socket. Same thing in do_dccp_getsockopt(). Add READ_ONCE()/WRITE_ONCE() annotations, and change dccp_sendmsg() to check again dccps_mss_cache after socket is locked. Fixes: 7c657876b63c ("[DCCP]: Initial implementation") Reported-by: syzbot Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20230803163021.2958262-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/dccp/output.c | 2 +- net/dccp/proto.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index b8a24734385e..fd2eb148d24d 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -187,7 +187,7 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu) /* And store cached results */ icsk->icsk_pmtu_cookie = pmtu; - dp->dccps_mss_cache = cur_mps; + WRITE_ONCE(dp->dccps_mss_cache, cur_mps); return cur_mps; } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index f331e5977a84..4e3266e4d7c3 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -630,7 +630,7 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); case DCCP_SOCKOPT_GET_CUR_MPS: - val = dp->dccps_mss_cache; + val = READ_ONCE(dp->dccps_mss_cache); break; case DCCP_SOCKOPT_AVAILABLE_CCIDS: return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen); @@ -739,7 +739,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) trace_dccp_probe(sk, len); - if (len > dp->dccps_mss_cache) + if (len > READ_ONCE(dp->dccps_mss_cache)) return -EMSGSIZE; lock_sock(sk); @@ -772,6 +772,12 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto out_discard; } + /* We need to check dccps_mss_cache after socket is locked. */ + if (len > dp->dccps_mss_cache) { + rc = -EMSGSIZE; + goto out_discard; + } + skb_reserve(skb, sk->sk_prot->max_header); rc = memcpy_from_msg(skb_put(skb, len), msg, len); if (rc != 0) -- cgit v1.2.3 From 95848dcb9d676738411a8ff70a9704039f1b3982 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 5 Aug 2023 07:55:37 +0200 Subject: zram: take device and not only bvec offset into account Commit af8b04c63708 ("zram: simplify bvec iteration in __zram_make_request") changed the bio iteration in zram to rely on the implicit capping to page boundaries in bio_for_each_segment. But it failed to care for the fact zram not only care about the page alignment of the bio payload, but also the page alignment into the device. For buffered I/O and swap those are the same, but for direct I/O or kernel internal I/O like XFS log buffer writes they can differ. Fix this by open coding bio_for_each_segment and limiting the bvec len so that it never crosses over a page alignment boundary in the device in addition to the payload boundary already taken care of by bio_iter_iovec. Cc: stable@vger.kernel.org Fixes: af8b04c63708 ("zram: simplify bvec iteration in __zram_make_request") Reported-by: Dusty Mabe Signed-off-by: Christoph Hellwig Acked-by: Sergey Senozhatsky Link: https://lore.kernel.org/r/20230805055537.147835-1-hch@lst.de Signed-off-by: Jens Axboe --- drivers/block/zram/zram_drv.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 5676e6dd5b16..06673c6ca255 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1870,15 +1870,16 @@ static void zram_bio_discard(struct zram *zram, struct bio *bio) static void zram_bio_read(struct zram *zram, struct bio *bio) { - struct bvec_iter iter; - struct bio_vec bv; - unsigned long start_time; + unsigned long start_time = bio_start_io_acct(bio); + struct bvec_iter iter = bio->bi_iter; - start_time = bio_start_io_acct(bio); - bio_for_each_segment(bv, bio, iter) { + do { u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + struct bio_vec bv = bio_iter_iovec(bio, iter); + + bv.bv_len = min_t(u32, bv.bv_len, PAGE_SIZE - offset); if (zram_bvec_read(zram, &bv, index, offset, bio) < 0) { atomic64_inc(&zram->stats.failed_reads); @@ -1890,22 +1891,26 @@ static void zram_bio_read(struct zram *zram, struct bio *bio) zram_slot_lock(zram, index); zram_accessed(zram, index); zram_slot_unlock(zram, index); - } + + bio_advance_iter_single(bio, &iter, bv.bv_len); + } while (iter.bi_size); + bio_end_io_acct(bio, start_time); bio_endio(bio); } static void zram_bio_write(struct zram *zram, struct bio *bio) { - struct bvec_iter iter; - struct bio_vec bv; - unsigned long start_time; + unsigned long start_time = bio_start_io_acct(bio); + struct bvec_iter iter = bio->bi_iter; - start_time = bio_start_io_acct(bio); - bio_for_each_segment(bv, bio, iter) { + do { u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + struct bio_vec bv = bio_iter_iovec(bio, iter); + + bv.bv_len = min_t(u32, bv.bv_len, PAGE_SIZE - offset); if (zram_bvec_write(zram, &bv, index, offset, bio) < 0) { atomic64_inc(&zram->stats.failed_writes); @@ -1916,7 +1921,10 @@ static void zram_bio_write(struct zram *zram, struct bio *bio) zram_slot_lock(zram, index); zram_accessed(zram, index); zram_slot_unlock(zram, index); - } + + bio_advance_iter_single(bio, &iter, bv.bv_len); + } while (iter.bi_size); + bio_end_io_acct(bio, start_time); bio_endio(bio); } -- cgit v1.2.3 From 5aa4fda5aa9c2a5a7bac67b4a12b089ab81fee3c Mon Sep 17 00:00:00 2001 From: Long Li Date: Sat, 29 Jul 2023 11:36:18 +0800 Subject: ksmbd: validate command request size In commit 2b9b8f3b68ed ("ksmbd: validate command payload size"), except for SMB2_OPLOCK_BREAK_HE command, the request size of other commands is not checked, it's not expected. Fix it by add check for request size of other commands. Cc: stable@vger.kernel.org Fixes: 2b9b8f3b68ed ("ksmbd: validate command payload size") Acked-by: Namjae Jeon Signed-off-by: Long Li Signed-off-by: Steve French --- fs/smb/server/smb2misc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index 33b7e6c4ceff..e881df1d10cb 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -380,13 +380,13 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) } if (smb2_req_struct_sizes[command] != pdu->StructureSize2) { - if (command == SMB2_OPLOCK_BREAK_HE && - le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 && - le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) { + if (!(command == SMB2_OPLOCK_BREAK_HE && + (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 || + le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_21))) { /* special case for SMB2.1 lease break message */ ksmbd_debug(SMB, - "Illegal request size %d for oplock break\n", - le16_to_cpu(pdu->StructureSize2)); + "Illegal request size %u for command %d\n", + le16_to_cpu(pdu->StructureSize2), command); return 1; } } -- cgit v1.2.3 From 79ed288cef201f1f212dfb934bcaac75572fb8f6 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 6 Aug 2023 08:44:17 +0900 Subject: ksmbd: fix wrong next length validation of ea buffer in smb2_set_ea() There are multiple smb2_ea_info buffers in FILE_FULL_EA_INFORMATION request from client. ksmbd find next smb2_ea_info using ->NextEntryOffset of current smb2_ea_info. ksmbd need to validate buffer length Before accessing the next ea. ksmbd should check buffer length using buf_len, not next variable. next is the start offset of current ea that got from previous ea. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21598 Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 9849d7489345..7cc1b0c47d0a 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2324,9 +2324,16 @@ next: break; buf_len -= next; eabuf = (struct smb2_ea_info *)((char *)eabuf + next); - if (next < (u32)eabuf->EaNameLength + le16_to_cpu(eabuf->EaValueLength)) + if (buf_len < sizeof(struct smb2_ea_info)) { + rc = -EINVAL; break; + } + if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + + le16_to_cpu(eabuf->EaValueLength)) { + rc = -EINVAL; + break; + } } while (next != 0); kfree(attr_name); -- cgit v1.2.3 From 6b47808f223c70ff564f9b363446d2a5fa1e05b2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 4 Aug 2023 15:59:51 -0700 Subject: net: tls: avoid discarding data on record close TLS records end with a 16B tag. For TLS device offload we only need to make space for this tag in the stream, the device will generate and replace it with the actual calculated tag. Long time ago the code would just re-reference the head frag which mostly worked but was suboptimal because it prevented TCP from combining the record into a single skb frag. I'm not sure if it was correct as the first frag may be shorter than the tag. The commit under fixes tried to replace that with using the page frag and if the allocation failed rolling back the data, if record was long enough. It achieves better fragment coalescing but is also buggy. We don't roll back the iterator, so unless we're at the end of send we'll skip the data we designated as tag and start the next record as if the rollback never happened. There's also the possibility that the record was constructed with MSG_MORE and the data came from a different syscall and we already told the user space that we "got it". Allocate a single dummy page and use it as fallback. Found by code inspection, and proven by forcing allocation failures. Fixes: e7b159a48ba6 ("net/tls: remove the record tail optimization") Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/tls/tls_device.c | 64 +++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 2021fe557e50..529101eb20bd 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -52,6 +52,8 @@ static LIST_HEAD(tls_device_list); static LIST_HEAD(tls_device_down_list); static DEFINE_SPINLOCK(tls_device_lock); +static struct page *dummy_page; + static void tls_device_free_ctx(struct tls_context *ctx) { if (ctx->tx_conf == TLS_HW) { @@ -312,36 +314,33 @@ static int tls_push_record(struct sock *sk, return tls_push_sg(sk, ctx, offload_ctx->sg_tx_data, 0, flags); } -static int tls_device_record_close(struct sock *sk, - struct tls_context *ctx, - struct tls_record_info *record, - struct page_frag *pfrag, - unsigned char record_type) +static void tls_device_record_close(struct sock *sk, + struct tls_context *ctx, + struct tls_record_info *record, + struct page_frag *pfrag, + unsigned char record_type) { struct tls_prot_info *prot = &ctx->prot_info; - int ret; + struct page_frag dummy_tag_frag; /* append tag * device will fill in the tag, we just need to append a placeholder * use socket memory to improve coalescing (re-using a single buffer * increases frag count) - * if we can't allocate memory now, steal some back from data + * if we can't allocate memory now use the dummy page */ - if (likely(skb_page_frag_refill(prot->tag_size, pfrag, - sk->sk_allocation))) { - ret = 0; - tls_append_frag(record, pfrag, prot->tag_size); - } else { - ret = prot->tag_size; - if (record->len <= prot->overhead_size) - return -ENOMEM; + if (unlikely(pfrag->size - pfrag->offset < prot->tag_size) && + !skb_page_frag_refill(prot->tag_size, pfrag, sk->sk_allocation)) { + dummy_tag_frag.page = dummy_page; + dummy_tag_frag.offset = 0; + pfrag = &dummy_tag_frag; } + tls_append_frag(record, pfrag, prot->tag_size); /* fill prepend */ tls_fill_prepend(ctx, skb_frag_address(&record->frags[0]), record->len - prot->overhead_size, record_type); - return ret; } static int tls_create_new_record(struct tls_offload_context_tx *offload_ctx, @@ -541,18 +540,8 @@ last_record: if (done || record->len >= max_open_record_len || (record->num_frags >= MAX_SKB_FRAGS - 1)) { - rc = tls_device_record_close(sk, tls_ctx, record, - pfrag, record_type); - if (rc) { - if (rc > 0) { - size += rc; - } else { - size = orig_size; - destroy_record(record); - ctx->open_record = NULL; - break; - } - } + tls_device_record_close(sk, tls_ctx, record, + pfrag, record_type); rc = tls_push_record(sk, tls_ctx, @@ -1450,14 +1439,26 @@ int __init tls_device_init(void) { int err; - destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0); - if (!destruct_wq) + dummy_page = alloc_page(GFP_KERNEL); + if (!dummy_page) return -ENOMEM; + destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0); + if (!destruct_wq) { + err = -ENOMEM; + goto err_free_dummy; + } + err = register_netdevice_notifier(&tls_dev_notifier); if (err) - destroy_workqueue(destruct_wq); + goto err_destroy_wq; + return 0; + +err_destroy_wq: + destroy_workqueue(destruct_wq); +err_free_dummy: + put_page(dummy_page); return err; } @@ -1466,4 +1467,5 @@ void __exit tls_device_cleanup(void) unregister_netdevice_notifier(&tls_dev_notifier); destroy_workqueue(destruct_wq); clean_acked_data_flush(); + put_page(dummy_page); } -- cgit v1.2.3 From 32d0a49d36a2a306c2e47fe5659361e424f0ed3f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 4 Aug 2023 17:26:52 +0000 Subject: macsec: use DEV_STATS_INC() syzbot/KCSAN reported data-races in macsec whenever dev->stats fields are updated. It appears all of these updates can happen from multiple cpus. Adopt SMP safe DEV_STATS_INC() to update dev->stats fields. Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Sabrina Dubroca Signed-off-by: David S. Miller --- drivers/net/macsec.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 984dfa5d6c11..144ec756c796 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -743,7 +743,7 @@ static bool macsec_post_decrypt(struct sk_buff *skb, struct macsec_secy *secy, u u64_stats_update_begin(&rxsc_stats->syncp); rxsc_stats->stats.InPktsLate++; u64_stats_update_end(&rxsc_stats->syncp); - secy->netdev->stats.rx_dropped++; + DEV_STATS_INC(secy->netdev, rx_dropped); return false; } @@ -767,7 +767,7 @@ static bool macsec_post_decrypt(struct sk_buff *skb, struct macsec_secy *secy, u rxsc_stats->stats.InPktsNotValid++; u64_stats_update_end(&rxsc_stats->syncp); this_cpu_inc(rx_sa->stats->InPktsNotValid); - secy->netdev->stats.rx_errors++; + DEV_STATS_INC(secy->netdev, rx_errors); return false; } @@ -1069,7 +1069,7 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb) u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsNoTag++; u64_stats_update_end(&secy_stats->syncp); - macsec->secy.netdev->stats.rx_dropped++; + DEV_STATS_INC(macsec->secy.netdev, rx_dropped); continue; } @@ -1179,7 +1179,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsBadTag++; u64_stats_update_end(&secy_stats->syncp); - secy->netdev->stats.rx_errors++; + DEV_STATS_INC(secy->netdev, rx_errors); goto drop_nosa; } @@ -1196,7 +1196,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) u64_stats_update_begin(&rxsc_stats->syncp); rxsc_stats->stats.InPktsNotUsingSA++; u64_stats_update_end(&rxsc_stats->syncp); - secy->netdev->stats.rx_errors++; + DEV_STATS_INC(secy->netdev, rx_errors); if (active_rx_sa) this_cpu_inc(active_rx_sa->stats->InPktsNotUsingSA); goto drop_nosa; @@ -1230,7 +1230,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) u64_stats_update_begin(&rxsc_stats->syncp); rxsc_stats->stats.InPktsLate++; u64_stats_update_end(&rxsc_stats->syncp); - macsec->secy.netdev->stats.rx_dropped++; + DEV_STATS_INC(macsec->secy.netdev, rx_dropped); goto drop; } } @@ -1271,7 +1271,7 @@ deliver: if (ret == NET_RX_SUCCESS) count_rx(dev, len); else - macsec->secy.netdev->stats.rx_dropped++; + DEV_STATS_INC(macsec->secy.netdev, rx_dropped); rcu_read_unlock(); @@ -1308,7 +1308,7 @@ nosci: u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsNoSCI++; u64_stats_update_end(&secy_stats->syncp); - macsec->secy.netdev->stats.rx_errors++; + DEV_STATS_INC(macsec->secy.netdev, rx_errors); continue; } @@ -1327,7 +1327,7 @@ nosci: secy_stats->stats.InPktsUnknownSCI++; u64_stats_update_end(&secy_stats->syncp); } else { - macsec->secy.netdev->stats.rx_dropped++; + DEV_STATS_INC(macsec->secy.netdev, rx_dropped); } } @@ -3422,7 +3422,7 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, if (!secy->operational) { kfree_skb(skb); - dev->stats.tx_dropped++; + DEV_STATS_INC(dev, tx_dropped); return NETDEV_TX_OK; } @@ -3430,7 +3430,7 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, skb = macsec_encrypt(skb, dev); if (IS_ERR(skb)) { if (PTR_ERR(skb) != -EINPROGRESS) - dev->stats.tx_dropped++; + DEV_STATS_INC(dev, tx_dropped); return NETDEV_TX_OK; } @@ -3667,9 +3667,9 @@ static void macsec_get_stats64(struct net_device *dev, dev_fetch_sw_netstats(s, dev->tstats); - s->rx_dropped = dev->stats.rx_dropped; - s->tx_dropped = dev->stats.tx_dropped; - s->rx_errors = dev->stats.rx_errors; + s->rx_dropped = atomic_long_read(&dev->stats.__rx_dropped); + s->tx_dropped = atomic_long_read(&dev->stats.__tx_dropped); + s->rx_errors = atomic_long_read(&dev->stats.__rx_errors); } static int macsec_get_iflink(const struct net_device *dev) -- cgit v1.2.3 From a0fc452a5d7fed986205539259df1d60546f536c Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sun, 6 Aug 2023 02:11:58 +1000 Subject: open: make RESOLVE_CACHED correctly test for O_TMPFILE O_TMPFILE is actually __O_TMPFILE|O_DIRECTORY. This means that the old fast-path check for RESOLVE_CACHED would reject all users passing O_DIRECTORY with -EAGAIN, when in fact the intended test was to check for __O_TMPFILE. Cc: stable@vger.kernel.org # v5.12+ Fixes: 99668f618062 ("fs: expose LOOKUP_CACHED through openat2() RESOLVE_CACHED") Signed-off-by: Aleksa Sarai Message-Id: <20230806-resolve_cached-o_tmpfile-v1-1-7ba16308465e@cyphar.com> Signed-off-by: Christian Brauner --- fs/open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/open.c b/fs/open.c index 0c55c8e7f837..e6ead0f19964 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1322,7 +1322,7 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) lookup_flags |= LOOKUP_IN_ROOT; if (how->resolve & RESOLVE_CACHED) { /* Don't bother even trying for create/truncate/tmpfile open */ - if (flags & (O_TRUNC | O_CREAT | O_TMPFILE)) + if (flags & (O_TRUNC | O_CREAT | __O_TMPFILE)) return -EAGAIN; lookup_flags |= LOOKUP_CACHED; } -- cgit v1.2.3 From 0a2c2baafa312ac4cec4f0bababedab3f971f224 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 5 Aug 2023 10:49:31 -0700 Subject: proc: fix missing conversion to 'iterate_shared' I'm looking at the directory handling due to the discussion about f_pos locking (see commit 797964253d35: "file: reinstate f_pos locking optimization for regular files"), and wanting to clean that up. And one source of ugliness is how we were supposed to move filesystems over to the '->iterate_shared()' function that only takes the inode lock for reading many many years ago, but several filesystems still use the bad old '->iterate()' that takes the inode lock for exclusive access. See commit 6192269444eb ("introduce a parallel variant of ->iterate()") that also added some documentation stating Old method is only used if the new one is absent; eventually it will be removed. Switch while you still can; the old one won't stay. and that was back in April 2016. Here we are, many years later, and the old version is still clearly sadly alive and well. Now, some of those old style iterators are probably just because the filesystem may end up having per-inode mutable data that it uses for iterating a directory, but at least one case is just a mistake. Al switched over most filesystems to use '->iterate_shared()' back when it was introduced. In particular, the /proc filesystem was converted as one of the first ones in commit f50752eaa0b0 ("switch all procfs directories ->iterate_shared()"). But then later one new user of '->iterate()' was then re-introduced by commit 6d9c939dbe4d ("procfs: add smack subdir to attrs"). And that's clearly not what we wanted, since that new case just uses the same 'proc_pident_readdir()' and 'proc_pident_lookup()' helper functions that other /proc pident directories use, and they are most definitely safe to use with the inode lock held shared. So just fix it. This still leaves a fair number of oddball filesystems using the old-style directory iterator (ceph, coda, exfat, jfs, ntfs, ocfs2, overlayfs, and vboxsf), but at least we don't have any remaining in the core filesystems. I'm going to add a wrapper function that just drops the read-lock and takes it as a write lock, so that we can clean up the core vfs layer and make all the ugly 'this filesystem needs exclusive inode locking' be just filesystem-internal warts. I just didn't want to make that conversion when we still had a core user left. Signed-off-by: Linus Torvalds Signed-off-by: Christian Brauner --- fs/proc/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 05452c3b9872..9df3f4839662 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2817,7 +2817,7 @@ static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ \ static const struct file_operations proc_##LSM##_attr_dir_ops = { \ .read = generic_read_dir, \ - .iterate = proc_##LSM##_attr_dir_iterate, \ + .iterate_shared = proc_##LSM##_attr_dir_iterate, \ .llseek = default_llseek, \ }; \ \ -- cgit v1.2.3 From 3e3271549670783be20e233a2b78a87a0b04c715 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 5 Aug 2023 12:25:01 -0700 Subject: vfs: get rid of old '->iterate' directory operation All users now just use '->iterate_shared()', which only takes the directory inode lock for reading. Filesystems that never got convered to shared mode now instead use a wrapper that drops the lock, re-takes it in write mode, calls the old function, and then downgrades the lock back to read mode. This way the VFS layer and other callers no longer need to care about filesystems that never got converted to the modern era. The filesystems that use the new wrapper are ceph, coda, exfat, jfs, ntfs, ocfs2, overlayfs, and vboxsf. Honestly, several of them look like they really could just iterate their directories in shared mode and skip the wrapper entirely, but the point of this change is to not change semantics or fix filesystems that haven't been fixed in the last 7+ years, but to finally get rid of the dual iterators. Signed-off-by: Linus Torvalds Signed-off-by: Christian Brauner --- Documentation/filesystems/locking.rst | 5 ++- Documentation/filesystems/porting.rst | 25 ++++++------- fs/ceph/dir.c | 5 +-- fs/coda/dir.c | 20 ++++------- fs/exfat/dir.c | 3 +- fs/exportfs/expfs.c | 2 +- fs/jfs/namei.c | 3 +- fs/ntfs/dir.c | 3 +- fs/ocfs2/file.c | 5 +-- fs/overlayfs/readdir.c | 3 +- fs/readdir.c | 68 ++++++++++++++++++++++++++--------- fs/vboxsf/dir.c | 3 +- include/linux/fs.h | 8 ++++- 13 files changed, 95 insertions(+), 58 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index ed148919e11a..0ca479dbb1cd 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -551,9 +551,8 @@ mutex or just to use i_size_read() instead. Note: this does not protect the file->f_pos against concurrent modifications since this is something the userspace has to take care about. -->iterate() is called with i_rwsem exclusive. - -->iterate_shared() is called with i_rwsem at least shared. +->iterate_shared() is called with i_rwsem held for reading, and with the +file f_pos_lock held exclusively ->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags. Most instances call fasync_helper(), which does that maintenance, so it's diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index d2d684ae7798..0f5da78ef4f9 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -537,7 +537,7 @@ vfs_readdir() is gone; switch to iterate_dir() instead **mandatory** -->readdir() is gone now; switch to ->iterate() +->readdir() is gone now; switch to ->iterate_shared() **mandatory** @@ -693,24 +693,19 @@ parallel now. --- -**recommended** +**mandatory** -->iterate_shared() is added; it's a parallel variant of ->iterate(). +->iterate_shared() is added. Exclusion on struct file level is still provided (as well as that between it and lseek on the same struct file), but if your directory has been opened several times, you can get these called in parallel. Exclusion between that method and all directory-modifying ones is still provided, of course. -Often enough ->iterate() can serve as ->iterate_shared() without any -changes - it is a read-only operation, after all. If you have any -per-inode or per-dentry in-core data structures modified by ->iterate(), -you might need something to serialize the access to them. If you -do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for -that; look for in-tree examples. - -Old method is only used if the new one is absent; eventually it will -be removed. Switch while you still can; the old one won't stay. +If you have any per-inode or per-dentry in-core data structures modified +by ->iterate_shared(), you might need something to serialize the access +to them. If you do dcache pre-seeding, you'll need to switch to +d_alloc_parallel() for that; look for in-tree examples. --- @@ -930,9 +925,9 @@ should be done by looking at FMODE_LSEEK in file->f_mode. filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: -callers never looked at specific -E... values anyway. ->iterate() and -->iterate_shared() instance require no changes at all, all filldir_t ones in -the tree converted. +callers never looked at specific -E... values anyway. -> iterate_shared() +instances require no changes at all, all filldir_t ones in the tree +converted. --- diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 4a2b39d9a61a..bdcffb04513f 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -2019,9 +2019,10 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) } } +WRAP_DIR_ITER(ceph_readdir) // FIXME! const struct file_operations ceph_dir_fops = { .read = ceph_read_dir, - .iterate = ceph_readdir, + .iterate_shared = shared_ceph_readdir, .llseek = ceph_dir_llseek, .open = ceph_open, .release = ceph_release, @@ -2033,7 +2034,7 @@ const struct file_operations ceph_dir_fops = { }; const struct file_operations ceph_snapdir_fops = { - .iterate = ceph_readdir, + .iterate_shared = shared_ceph_readdir, .llseek = ceph_dir_llseek, .open = ceph_open, .release = ceph_release, diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 8450b1bd354b..1b960de2bf39 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -429,21 +429,14 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx) cfi = coda_ftoc(coda_file); host_file = cfi->cfi_container; - if (host_file->f_op->iterate || host_file->f_op->iterate_shared) { + if (host_file->f_op->iterate_shared) { struct inode *host_inode = file_inode(host_file); ret = -ENOENT; if (!IS_DEADDIR(host_inode)) { - if (host_file->f_op->iterate_shared) { - inode_lock_shared(host_inode); - ret = host_file->f_op->iterate_shared(host_file, ctx); - file_accessed(host_file); - inode_unlock_shared(host_inode); - } else { - inode_lock(host_inode); - ret = host_file->f_op->iterate(host_file, ctx); - file_accessed(host_file); - inode_unlock(host_inode); - } + inode_lock_shared(host_inode); + ret = host_file->f_op->iterate_shared(host_file, ctx); + file_accessed(host_file); + inode_unlock_shared(host_inode); } return ret; } @@ -585,10 +578,11 @@ const struct inode_operations coda_dir_inode_operations = { .setattr = coda_setattr, }; +WRAP_DIR_ITER(coda_readdir) // FIXME! const struct file_operations coda_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, - .iterate = coda_readdir, + .iterate_shared = shared_coda_readdir, .open = coda_open, .release = coda_release, .fsync = coda_fsync, diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 598081d0d059..e1586bba6d86 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -306,10 +306,11 @@ out: return err; } +WRAP_DIR_ITER(exfat_iterate) // FIXME! const struct file_operations exfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, - .iterate = exfat_iterate, + .iterate_shared = shared_exfat_iterate, .unlocked_ioctl = exfat_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = exfat_compat_ioctl, diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 40e624cf7e92..d1dbe47c7975 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -315,7 +315,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child) goto out; error = -EINVAL; - if (!file->f_op->iterate && !file->f_op->iterate_shared) + if (!file->f_op->iterate_shared) goto out_close; buffer.sequence = 0; diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 9b030297aa64..e98ddb2b1cf2 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1535,9 +1535,10 @@ const struct inode_operations jfs_dir_inode_operations = { #endif }; +WRAP_DIR_ITER(jfs_readdir) // FIXME! const struct file_operations jfs_dir_operations = { .read = generic_read_dir, - .iterate = jfs_readdir, + .iterate_shared = shared_jfs_readdir, .fsync = jfs_fsync, .unlocked_ioctl = jfs_ioctl, .compat_ioctl = compat_ptr_ioctl, diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 518c3a21a556..4596c90e7b7c 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -1525,10 +1525,11 @@ static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, #endif /* NTFS_RW */ +WRAP_DIR_ITER(ntfs_readdir) // FIXME! const struct file_operations ntfs_dir_ops = { .llseek = generic_file_llseek, /* Seek inside directory. */ .read = generic_read_dir, /* Return -EISDIR. */ - .iterate = ntfs_readdir, /* Read directory contents. */ + .iterate_shared = shared_ntfs_readdir, /* Read directory contents. */ #ifdef NTFS_RW .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */ #endif /* NTFS_RW */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 91a194596552..bf2c17ea96a0 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2793,10 +2793,11 @@ const struct file_operations ocfs2_fops = { .remap_file_range = ocfs2_remap_file_range, }; +WRAP_DIR_ITER(ocfs2_readdir) // FIXME! const struct file_operations ocfs2_dops = { .llseek = generic_file_llseek, .read = generic_read_dir, - .iterate = ocfs2_readdir, + .iterate_shared = shared_ocfs2_readdir, .fsync = ocfs2_sync_file, .release = ocfs2_dir_release, .open = ocfs2_dir_open, @@ -2842,7 +2843,7 @@ const struct file_operations ocfs2_fops_no_plocks = { const struct file_operations ocfs2_dops_no_plocks = { .llseek = generic_file_llseek, .read = generic_read_dir, - .iterate = ocfs2_readdir, + .iterate_shared = shared_ocfs2_readdir, .fsync = ocfs2_sync_file, .release = ocfs2_dir_release, .open = ocfs2_dir_open, diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index ee5c4736480f..de39e067ae65 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -954,10 +954,11 @@ static int ovl_dir_open(struct inode *inode, struct file *file) return 0; } +WRAP_DIR_ITER(ovl_iterate) // FIXME! const struct file_operations ovl_dir_operations = { .read = generic_read_dir, .open = ovl_dir_open, - .iterate = ovl_iterate, + .iterate_shared = shared_ovl_iterate, .llseek = ovl_dir_llseek, .fsync = ovl_dir_fsync, .release = ovl_dir_release, diff --git a/fs/readdir.c b/fs/readdir.c index b264ce60114d..c8c46e294431 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -24,6 +24,53 @@ #include +/* + * Some filesystems were never converted to '->iterate_shared()' + * and their directory iterators want the inode lock held for + * writing. This wrapper allows for converting from the shared + * semantics to the exclusive inode use. + */ +int wrap_directory_iterator(struct file *file, + struct dir_context *ctx, + int (*iter)(struct file *, struct dir_context *)) +{ + struct inode *inode = file_inode(file); + int ret; + + /* + * We'd love to have an 'inode_upgrade_trylock()' operation, + * see the comment in mmap_upgrade_trylock() in mm/memory.c. + * + * But considering this is for "filesystems that never got + * converted", it really doesn't matter. + * + * Also note that since we have to return with the lock held + * for reading, we can't use the "killable()" locking here, + * since we do need to get the lock even if we're dying. + * + * We could do the write part killably and then get the read + * lock unconditionally if it mattered, but see above on why + * this does the very simplistic conversion. + */ + up_read(&inode->i_rwsem); + down_write(&inode->i_rwsem); + + /* + * Since we dropped the inode lock, we should do the + * DEADDIR test again. See 'iterate_dir()' below. + * + * Note that we don't need to re-do the f_pos games, + * since the file must be locked wrt f_pos anyway. + */ + ret = -ENOENT; + if (!IS_DEADDIR(inode)) + ret = iter(file, ctx); + + downgrade_write(&inode->i_rwsem); + return ret; +} +EXPORT_SYMBOL(wrap_directory_iterator); + /* * Note the "unsafe_put_user() semantics: we goto a * label for errors. @@ -40,39 +87,28 @@ int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); - bool shared = false; int res = -ENOTDIR; - if (file->f_op->iterate_shared) - shared = true; - else if (!file->f_op->iterate) + + if (!file->f_op->iterate_shared) goto out; res = security_file_permission(file, MAY_READ); if (res) goto out; - if (shared) - res = down_read_killable(&inode->i_rwsem); - else - res = down_write_killable(&inode->i_rwsem); + res = down_read_killable(&inode->i_rwsem); if (res) goto out; res = -ENOENT; if (!IS_DEADDIR(inode)) { ctx->pos = file->f_pos; - if (shared) - res = file->f_op->iterate_shared(file, ctx); - else - res = file->f_op->iterate(file, ctx); + res = file->f_op->iterate_shared(file, ctx); file->f_pos = ctx->pos; fsnotify_access(file); file_accessed(file); } - if (shared) - inode_unlock_shared(inode); - else - inode_unlock(inode); + inode_unlock_shared(inode); out: return res; } diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c index 075f15c43c78..5f1a14d5b927 100644 --- a/fs/vboxsf/dir.c +++ b/fs/vboxsf/dir.c @@ -179,9 +179,10 @@ static int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx) return 0; } +WRAP_DIR_ITER(vboxsf_dir_iterate) // FIXME! const struct file_operations vboxsf_dir_fops = { .open = vboxsf_dir_open, - .iterate = vboxsf_dir_iterate, + .iterate_shared = shared_vboxsf_dir_iterate, .release = vboxsf_dir_release, .read = generic_read_dir, .llseek = generic_file_llseek, diff --git a/include/linux/fs.h b/include/linux/fs.h index 6867512907d6..562f2623c9c9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1780,7 +1780,6 @@ struct file_operations { ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *, unsigned int flags); - int (*iterate) (struct file *, struct dir_context *); int (*iterate_shared) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); @@ -1817,6 +1816,13 @@ struct file_operations { unsigned int poll_flags); } __randomize_layout; +/* Wrap a directory iterator that needs exclusive inode access */ +int wrap_directory_iterator(struct file *, struct dir_context *, + int (*) (struct file *, struct dir_context *)); +#define WRAP_DIR_ITER(x) \ + static int shared_##x(struct file *file , struct dir_context *ctx) \ + { return wrap_directory_iterator(file, ctx, x); } + struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *); -- cgit v1.2.3 From 7d84d1b9af6366aa9df1b523bdb7e002372e38d0 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 6 Aug 2023 14:49:35 +0200 Subject: fs: rely on ->iterate_shared to determine f_pos locking Now that we removed ->iterate we don't need to check for either ->iterate or ->iterate_shared in file_needs_f_pos_lock(). Simply check for ->iterate_shared instead. This will tell us whether we need to unconditionally take the lock. Not just does it allow us to avoid checking f_inode's mode it also actually clearly shows that we're locking because of readdir. Signed-off-by: Christian Brauner --- fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index dbca26ef7a01..3fd003a8604f 100644 --- a/fs/file.c +++ b/fs/file.c @@ -1049,7 +1049,7 @@ unsigned long __fdget_raw(unsigned int fd) static inline bool file_needs_f_pos_lock(struct file *file) { return (file->f_mode & FMODE_ATOMIC_POS) && - (file_count(file) > 1 || S_ISDIR(file_inode(file)->i_mode)); + (file_count(file) > 1 || file->f_op->iterate_shared); } unsigned long __fdget_pos(unsigned int fd) -- cgit v1.2.3 From f38963b9cd0645a336cf30c5da2e89e34e34fec3 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Fri, 4 Aug 2023 15:14:03 -0700 Subject: hwmon: (pmbus/bel-pfe) Enable PMBUS_SKIP_STATUS_CHECK for pfe1100 Skip status check for both pfe1100 and pfe3000 because the communication error is also observed on pfe1100 devices. Signed-off-by: Tao Ren Fixes: 626bb2f3fb3c hwmon: (pmbus) add driver for BEL PFE1100 and PFE3000 Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230804221403.28931-1-rentao.bupt@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/bel-pfe.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index fa5070ae26bc..7c5f4b10a7c1 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -17,12 +17,13 @@ enum chips {pfe1100, pfe3000}; /* - * Disable status check for pfe3000 devices, because some devices report - * communication error (invalid command) for VOUT_MODE command (0x20) - * although correct VOUT_MODE (0x16) is returned: it leads to incorrect - * exponent in linear mode. + * Disable status check because some devices report communication error + * (invalid command) for VOUT_MODE command (0x20) although the correct + * VOUT_MODE (0x16) is returned: it leads to incorrect exponent in linear + * mode. + * This affects both pfe3000 and pfe1100. */ -static struct pmbus_platform_data pfe3000_plat_data = { +static struct pmbus_platform_data pfe_plat_data = { .flags = PMBUS_SKIP_STATUS_CHECK, }; @@ -94,16 +95,15 @@ static int pfe_pmbus_probe(struct i2c_client *client) int model; model = (int)i2c_match_id(pfe_device_id, client)->driver_data; + client->dev.platform_data = &pfe_plat_data; /* * PFE3000-12-069RA devices may not stay in page 0 during device * probe which leads to probe failure (read status word failed). * So let's set the device to page 0 at the beginning. */ - if (model == pfe3000) { - client->dev.platform_data = &pfe3000_plat_data; + if (model == pfe3000) i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); - } return pmbus_do_probe(client, &pfe_driver_info[model]); } -- cgit v1.2.3 From b1c936e9af5dd08636d568736fc6075ed9d1d529 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Fri, 4 Aug 2023 18:53:36 +0300 Subject: drivers: vxlan: vnifilter: free percpu vni stats on error path In case rhashtable_lookup_insert_fast() fails inside vxlan_vni_add(), the allocated percpu vni stats are not freed on the error path. Introduce vxlan_vni_free() which would work as a nice wrapper to free vxlan_vni_node resources properly. Found by Linux Verification Center (linuxtesting.org). Fixes: 4095e0e1328a ("drivers: vxlan: vnifilter: per vni stats") Suggested-by: Ido Schimmel Signed-off-by: Fedor Pchelkin Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_vnifilter.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c index a3de081cda5e..c3ff30ab782e 100644 --- a/drivers/net/vxlan/vxlan_vnifilter.c +++ b/drivers/net/vxlan/vxlan_vnifilter.c @@ -713,6 +713,12 @@ static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan, return vninode; } +static void vxlan_vni_free(struct vxlan_vni_node *vninode) +{ + free_percpu(vninode->stats); + kfree(vninode); +} + static int vxlan_vni_add(struct vxlan_dev *vxlan, struct vxlan_vni_group *vg, u32 vni, union vxlan_addr *group, @@ -740,7 +746,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, &vninode->vnode, vxlan_vni_rht_params); if (err) { - kfree(vninode); + vxlan_vni_free(vninode); return err; } @@ -763,8 +769,7 @@ static void vxlan_vni_node_rcu_free(struct rcu_head *rcu) struct vxlan_vni_node *v; v = container_of(rcu, struct vxlan_vni_node, rcu); - free_percpu(v->stats); - kfree(v); + vxlan_vni_free(v); } static int vxlan_vni_del(struct vxlan_dev *vxlan, -- cgit v1.2.3 From 52417a95ff2d810dc31a68ae71102e741efea772 Mon Sep 17 00:00:00 2001 From: Nitya Sunkad Date: Fri, 4 Aug 2023 13:56:22 -0700 Subject: ionic: Add missing err handling for queue reconfig ionic_start_queues_reconfig returns an error code if txrx_init fails. Handle this error code in the relevant places. This fixes a corner case where the device could get left in a detached state if the CMB reconfig fails and the attempt to clean up the mess also fails. Note that calling netif_device_attach when the netdev is already attached does not lead to unexpected behavior. Change goto name "errout" to "err_out" to maintain consistency across goto statements. Fixes: 40bc471dc714 ("ionic: add tx/rx-push support with device Component Memory Buffers") Fixes: 6f7d6f0fd7a3 ("ionic: pull reset_queues into tx_timeout handler") Signed-off-by: Nitya Sunkad Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 612b0015dc43..432fb93aa801 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1817,6 +1817,7 @@ static int ionic_change_mtu(struct net_device *netdev, int new_mtu) static void ionic_tx_timeout_work(struct work_struct *ws) { struct ionic_lif *lif = container_of(ws, struct ionic_lif, tx_timeout_work); + int err; if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) return; @@ -1829,8 +1830,11 @@ static void ionic_tx_timeout_work(struct work_struct *ws) mutex_lock(&lif->queue_lock); ionic_stop_queues_reconfig(lif); - ionic_start_queues_reconfig(lif); + err = ionic_start_queues_reconfig(lif); mutex_unlock(&lif->queue_lock); + + if (err) + dev_err(lif->ionic->dev, "%s: Restarting queues failed\n", __func__); } static void ionic_tx_timeout(struct net_device *netdev, unsigned int txqueue) @@ -2800,17 +2804,22 @@ static int ionic_cmb_reconfig(struct ionic_lif *lif, if (err) { dev_err(lif->ionic->dev, "CMB restore failed: %d\n", err); - goto errout; + goto err_out; } } - ionic_start_queues_reconfig(lif); - } else { - /* This was detached in ionic_stop_queues_reconfig() */ - netif_device_attach(lif->netdev); + err = ionic_start_queues_reconfig(lif); + if (err) { + dev_err(lif->ionic->dev, + "CMB reconfig failed: %d\n", err); + goto err_out; + } } -errout: +err_out: + /* This was detached in ionic_stop_queues_reconfig() */ + netif_device_attach(lif->netdev); + return err; } -- cgit v1.2.3 From 0a46781c89dece85386885a407244ca26e5c1c44 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 12 Jul 2023 18:26:45 +0530 Subject: dmaengine: mcf-edma: Fix a potential un-allocated memory access When 'mcf_edma' is allocated, some space is allocated for a flexible array at the end of the struct. 'chans' item are allocated, that is to say 'pdata->dma_channels'. Then, this number of item is stored in 'mcf_edma->n_chans'. A few lines later, if 'mcf_edma->n_chans' is 0, then a default value of 64 is set. This ends to no space allocated by devm_kzalloc() because chans was 0, but 64 items are read and/or written in some not allocated memory. Change the logic to define a default value before allocating the memory. Fixes: e7a3ff92eaf1 ("dmaengine: fsl-edma: add ColdFire mcf5441x edma support") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/f55d914407c900828f6fad3ea5fa791a5f17b9a4.1685172449.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/mcf-edma.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c index ebd8733f72ad..9413fad08a60 100644 --- a/drivers/dma/mcf-edma.c +++ b/drivers/dma/mcf-edma.c @@ -190,7 +190,13 @@ static int mcf_edma_probe(struct platform_device *pdev) return -EINVAL; } - chans = pdata->dma_channels; + if (!pdata->dma_channels) { + dev_info(&pdev->dev, "setting default channel number to 64"); + chans = 64; + } else { + chans = pdata->dma_channels; + } + len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans; mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); if (!mcf_edma) @@ -202,11 +208,6 @@ static int mcf_edma_probe(struct platform_device *pdev) mcf_edma->drvdata = &mcf_data; mcf_edma->big_endian = 1; - if (!mcf_edma->n_chans) { - dev_info(&pdev->dev, "setting default channel number to 64"); - mcf_edma->n_chans = 64; - } - mutex_init(&mcf_edma->fsl_edma_mutex); mcf_edma->membase = devm_platform_ioremap_resource(pdev, 0); -- cgit v1.2.3 From e2dcbc330f46afb82fd49a6dcbb10f6cdcb466ec Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 7 Jul 2023 13:50:03 -0600 Subject: dmaengine: qcom_hidma: Update codeaurora email domain The codeaurora.org email domain is defunct and will bounce. Update entries to Sinan's kernel.org address which is the address in MAINTAINERS for this component. Signed-off-by: Jeffrey Hugo Acked-By: Sinan Kaya Link: https://lore.kernel.org/r/20230707195003.6619-1-quic_jhugo@quicinc.com Signed-off-by: Vinod Koul --- Documentation/ABI/testing/sysfs-platform-hidma | 2 +- Documentation/ABI/testing/sysfs-platform-hidma-mgmt | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-platform-hidma b/Documentation/ABI/testing/sysfs-platform-hidma index fca40a54df59..a80aeda85ef6 100644 --- a/Documentation/ABI/testing/sysfs-platform-hidma +++ b/Documentation/ABI/testing/sysfs-platform-hidma @@ -2,7 +2,7 @@ What: /sys/devices/platform/hidma-*/chid /sys/devices/platform/QCOM8061:*/chid Date: Dec 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the ID of the channel within the HIDMA instance. It is used to associate a given HIDMA channel with the diff --git a/Documentation/ABI/testing/sysfs-platform-hidma-mgmt b/Documentation/ABI/testing/sysfs-platform-hidma-mgmt index 3b6c5c9eabdc..0373745b4e18 100644 --- a/Documentation/ABI/testing/sysfs-platform-hidma-mgmt +++ b/Documentation/ABI/testing/sysfs-platform-hidma-mgmt @@ -2,7 +2,7 @@ What: /sys/devices/platform/hidma-mgmt*/chanops/chan*/priority /sys/devices/platform/QCOM8060:*/chanops/chan*/priority Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains either 0 or 1 and indicates if the DMA channel is a low priority (0) or high priority (1) channel. @@ -11,7 +11,7 @@ What: /sys/devices/platform/hidma-mgmt*/chanops/chan*/weight /sys/devices/platform/QCOM8060:*/chanops/chan*/weight Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains 0..15 and indicates the weight of the channel among equal priority channels during round robin scheduling. @@ -20,7 +20,7 @@ What: /sys/devices/platform/hidma-mgmt*/chreset_timeout_cycles /sys/devices/platform/QCOM8060:*/chreset_timeout_cycles Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the platform specific cycle value to wait after a reset command is issued. If the value is chosen too short, @@ -32,7 +32,7 @@ What: /sys/devices/platform/hidma-mgmt*/dma_channels /sys/devices/platform/QCOM8060:*/dma_channels Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains the number of dma channels supported by one instance of HIDMA hardware. The value may change from chip to chip. @@ -41,7 +41,7 @@ What: /sys/devices/platform/hidma-mgmt*/hw_version_major /sys/devices/platform/QCOM8060:*/hw_version_major Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Version number major for the hardware. @@ -49,7 +49,7 @@ What: /sys/devices/platform/hidma-mgmt*/hw_version_minor /sys/devices/platform/QCOM8060:*/hw_version_minor Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Version number minor for the hardware. @@ -57,7 +57,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_rd_xactions /sys/devices/platform/QCOM8060:*/max_rd_xactions Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains a value between 0 and 31. Maximum number of read transactions that can be issued back to back. @@ -69,7 +69,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_read_request /sys/devices/platform/QCOM8060:*/max_read_request Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Size of each read request. The value needs to be a power of two and can be between 128 and 1024. @@ -78,7 +78,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_wr_xactions /sys/devices/platform/QCOM8060:*/max_wr_xactions Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Contains a value between 0 and 31. Maximum number of write transactions that can be issued back to back. @@ -91,7 +91,7 @@ What: /sys/devices/platform/hidma-mgmt*/max_write_request /sys/devices/platform/QCOM8060:*/max_write_request Date: Nov 2015 KernelVersion: 4.4 -Contact: "Sinan Kaya " +Contact: "Sinan Kaya " Description: Size of each write request. The value needs to be a power of two and can be between 128 and 1024. -- cgit v1.2.3 From 8cda3ececf07d374774f6a13e5a94bc2dc04c26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 26 May 2023 13:54:34 +0300 Subject: dmaengine: pl330: Return DMA_PAUSED when transaction is paused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pl330_pause() does not set anything to indicate paused condition which causes pl330_tx_status() to return DMA_IN_PROGRESS. This breaks 8250 DMA flush after the fix in commit 57e9af7831dc ("serial: 8250_dma: Fix DMA Rx rearm race"). The function comment for pl330_pause() claims pause is supported but resume is not which is enough for 8250 DMA flush to work as long as DMA status reports DMA_PAUSED when appropriate. Add PAUSED state for descriptor and mark BUSY descriptors with PAUSED in pl330_pause(). Return DMA_PAUSED from pl330_tx_status() when the descriptor is PAUSED. Reported-by: Richard Tresidder Tested-by: Richard Tresidder Fixes: 88987d2c7534 ("dmaengine: pl330: add DMA_PAUSE feature") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/linux-serial/f8a86ecd-64b1-573f-c2fa-59f541083f1a@electromag.com.au/ Signed-off-by: Ilpo JĂ€rvinen Link: https://lore.kernel.org/r/20230526105434.14959-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index b4731fe6bbc1..3cf0b38387ae 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -403,6 +403,12 @@ enum desc_status { * of a channel can be BUSY at any time. */ BUSY, + /* + * Pause was called while descriptor was BUSY. Due to hardware + * limitations, only termination is possible for descriptors + * that have been paused. + */ + PAUSED, /* * Sitting on the channel work_list but xfer done * by PL330 core @@ -2041,7 +2047,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch) list_for_each_entry(desc, &pch->work_list, node) { /* If already submitted */ - if (desc->status == BUSY) + if (desc->status == BUSY || desc->status == PAUSED) continue; ret = pl330_submit_req(pch->thread, desc); @@ -2326,6 +2332,7 @@ static int pl330_pause(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); struct pl330_dmac *pl330 = pch->dmac; + struct dma_pl330_desc *desc; unsigned long flags; pm_runtime_get_sync(pl330->ddma.dev); @@ -2335,6 +2342,10 @@ static int pl330_pause(struct dma_chan *chan) _stop(pch->thread); spin_unlock(&pl330->lock); + list_for_each_entry(desc, &pch->work_list, node) { + if (desc->status == BUSY) + desc->status = PAUSED; + } spin_unlock_irqrestore(&pch->lock, flags); pm_runtime_mark_last_busy(pl330->ddma.dev); pm_runtime_put_autosuspend(pl330->ddma.dev); @@ -2425,7 +2436,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, else if (running && desc == running) transferred = pl330_get_current_xferred_count(pch, desc); - else if (desc->status == BUSY) + else if (desc->status == BUSY || desc->status == PAUSED) /* * Busy but not running means either just enqueued, * or finished and not yet marked done @@ -2442,6 +2453,9 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, case DONE: ret = DMA_COMPLETE; break; + case PAUSED: + ret = DMA_PAUSED; + break; case PREP: case BUSY: ret = DMA_IN_PROGRESS; -- cgit v1.2.3 From 863676fe1ac1b82fc9eb56c242e80acfbfc18b76 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Wed, 12 Jul 2023 12:35:05 -0700 Subject: dmaengine: idxd: Clear PRS disable flag when disabling IDXD device Disabling IDXD device doesn't reset Page Request Service (PRS) disable flag to its initial value 0. This may cause user confusion because once PRS is disabled user will see PRS still remains the previous setting (i.e. disabled) via sysfs interface even after the device is disabled. To eliminate user confusion, reset PRS disable flag to ensure that the PRS flag bit reflects correct state after the device is disabled. Additionally, simplify the code by setting wq->flags to 0, which clears all flag bits, including any future additions. Fixes: f2dc327131b5 ("dmaengine: idxd: add per wq PRS disable") Tested-by: Tony Zhu Signed-off-by: Fenghua Yu Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/20230712193505.3440752-1-fenghua.yu@intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5abbcc61c528..9a15f0d12c79 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -384,9 +384,7 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq) wq->threshold = 0; wq->priority = 0; wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; - clear_bit(WQ_FLAG_DEDICATED, &wq->flags); - clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); - clear_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); + wq->flags = 0; memset(wq->name, 0, WQ_NAME_SIZE); wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER; idxd_wq_set_max_batch_size(idxd->data->type, wq, WQ_DEFAULT_MAX_BATCH); -- cgit v1.2.3 From 74d7221c1f9c9f3a8c316a3557ca7dca8b99d14c Mon Sep 17 00:00:00 2001 From: Zhang Jianhua Date: Sat, 22 Jul 2023 15:32:44 +0000 Subject: dmaengine: owl-dma: Modify mismatched function name No functional modification involved. drivers/dma/owl-dma.c:208: warning: expecting prototype for struct owl_dma_pchan. Prototype was for struct owl_dma_vchan instead HDRTEST usr/include/sound/asequencer.h Fixes: 47e20577c24d ("dmaengine: Add Actions Semi Owl family S900 DMA driver") Signed-off-by: Zhang Jianhua Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20230722153244.2086949-1-chris.zjh@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/owl-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c index 95a462a1f511..b6e0ac8314e5 100644 --- a/drivers/dma/owl-dma.c +++ b/drivers/dma/owl-dma.c @@ -192,7 +192,7 @@ struct owl_dma_pchan { }; /** - * struct owl_dma_pchan - Wrapper for DMA ENGINE channel + * struct owl_dma_vchan - Wrapper for DMA ENGINE channel * @vc: wrapped virtual channel * @pchan: the physical channel utilized by this channel * @txd: active transaction on this channel -- cgit v1.2.3 From 96891e90d1256b569b1c183e7c9a0cfc568fa3b0 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 31 Jul 2023 12:14:39 +0200 Subject: dmaengine: xilinx: xdma: Fix interrupt vector setting A couple of hardware registers need to be set to reflect which interrupts have been allocated to the device. Each register is 32-bit wide and can receive four 8-bit values. If we provide any other interrupt number than four, the irq_num variable will never be 0 within the while check and the while block will loop forever. There is an easy way to prevent this: just break the for loop when we reach "irq_num == 0", which anyway means all interrupts have been processed. Cc: stable@vger.kernel.org Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Signed-off-by: Miquel Raynal Acked-by: Lizhi Hou Link: https://lore.kernel.org/r/20230731101442.792514-2-miquel.raynal@bootlin.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xdma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index ad5ff63354cf..5116188b9977 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -668,6 +668,8 @@ static int xdma_set_vector_reg(struct xdma_device *xdev, u32 vec_tbl_start, val |= irq_start << shift; irq_start++; irq_num--; + if (!irq_num) + break; } /* write IRQ register */ -- cgit v1.2.3 From 422dbc66b7702ae797326d5480c3c9b6467053da Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 31 Jul 2023 12:14:40 +0200 Subject: dmaengine: xilinx: xdma: Fix typo Probably a copy/paste error with the previous block, here we are actually managing C2H IRQs. Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230731101442.792514-3-miquel.raynal@bootlin.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 5116188b9977..e0bfd129d563 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -717,7 +717,7 @@ static int xdma_irq_init(struct xdma_device *xdev) ret = request_irq(irq, xdma_channel_isr, 0, "xdma-c2h-channel", &xdev->c2h_chans[j]); if (ret) { - xdma_err(xdev, "H2C channel%d request irq%d failed: %d", + xdma_err(xdev, "C2H channel%d request irq%d failed: %d", j, irq, ret); goto failed_init_c2h; } -- cgit v1.2.3 From 52a93d39b17dc7eb98b6aa3edb93943248e03b2f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Aug 2023 15:07:51 -0700 Subject: Linux 6.5-rc5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 653238528aac..6bbf9db6b414 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 5 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* -- cgit v1.2.3 From 5a15d8348881e9371afdf9f5357a135489496955 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Mon, 7 Aug 2023 10:46:04 +0200 Subject: x86/srso: Tie SBPB bit setting to microcode patch detection The SBPB bit in MSR_IA32_PRED_CMD is supported only after a microcode patch has been applied so set X86_FEATURE_SBPB only then. Otherwise, guests would attempt to set that bit and #GP on the MSR write. While at it, make SMT detection more robust as some guests - depending on how and what CPUID leafs their report - lead to cpu_smt_control getting set to CPU_SMT_NOT_SUPPORTED but SRSO_NO should be set for any guest incarnation where one simply cannot do SMT, for whatever reason. Fixes: fb3bd914b3ec ("x86/srso: Add a Speculative RAS Overflow mitigation") Reported-by: Konrad Rzeszutek Wilk Reported-by: Salvatore Bonaccorso Signed-off-by: Borislav Petkov (AMD) --- arch/x86/kernel/cpu/amd.c | 19 ++++++++++++------- arch/x86/kernel/cpu/bugs.c | 7 +++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 834f310b2f1a..41e10c26efb5 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1238,14 +1238,19 @@ EXPORT_SYMBOL_GPL(amd_get_highest_perf); bool cpu_has_ibpb_brtype_microcode(void) { - u8 fam = boot_cpu_data.x86; - + switch (boot_cpu_data.x86) { /* Zen1/2 IBPB flushes branch type predictions too. */ - if (fam == 0x17) + case 0x17: return boot_cpu_has(X86_FEATURE_AMD_IBPB); - /* Poke the MSR bit on Zen3/4 to check its presence. */ - else if (fam == 0x19) - return !wrmsrl_safe(MSR_IA32_PRED_CMD, PRED_CMD_SBPB); - else + case 0x19: + /* Poke the MSR bit on Zen3/4 to check its presence. */ + if (!wrmsrl_safe(MSR_IA32_PRED_CMD, PRED_CMD_SBPB)) { + setup_force_cpu_cap(X86_FEATURE_SBPB); + return true; + } else { + return false; + } + default: return false; + } } diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 7314a6bdc862..2afe69bff218 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2265,14 +2265,13 @@ static void __init srso_select_mitigation(void) * flags for guests. */ setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE); - setup_force_cpu_cap(X86_FEATURE_SBPB); /* * Zen1/2 with SMT off aren't vulnerable after the right * IBPB microcode has been applied. */ if ((boot_cpu_data.x86 < 0x19) && - (cpu_smt_control == CPU_SMT_DISABLED)) + (!cpu_smt_possible() || (cpu_smt_control == CPU_SMT_DISABLED))) setup_force_cpu_cap(X86_FEATURE_SRSO_NO); } @@ -2345,8 +2344,8 @@ static void __init srso_select_mitigation(void) pr_info("%s%s\n", srso_strings[srso_mitigation], (has_microcode ? "" : ", no microcode")); pred_cmd: - if (boot_cpu_has(X86_FEATURE_SRSO_NO) || - srso_cmd == SRSO_CMD_OFF) + if ((boot_cpu_has(X86_FEATURE_SRSO_NO) || srso_cmd == SRSO_CMD_OFF) && + boot_cpu_has(X86_FEATURE_SBPB)) x86_pred_cmd = PRED_CMD_SBPB; } -- cgit v1.2.3 From df2f7cde73cb58c0e6a60f97d1cd6037138a45cd Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Mon, 7 Aug 2023 10:33:57 +0200 Subject: PM: hibernate: fix resume_store() return value when hibernation not available On a laptop with hibernation set up but not actively used, and with secure boot and lockdown enabled kernel, 6.5-rc1 gets stuck on boot with the following repeated messages: A start job is running for Resume from hibernation using device /dev/system/swap (24s / no limit) lockdown_is_locked_down: 25311154 callbacks suppressed Lockdown: systemd-hiberna: hibernation is restricted; see man kernel_lockdown.7 ... Checking the resume code leads to commit cc89c63e2fe3 ("PM: hibernate: move finding the resume device out of software_resume") which inadvertently changed the return value from resume_store() to 0 when !hibernation_available(). This apparently translates to userspace write() returning 0 as in number of bytes written, and userspace looping indefinitely in the attempt to write the intended value. Fix this by returning the full number of bytes that were to be written, as that's what was done before the commit. Fixes: cc89c63e2fe3 ("PM: hibernate: move finding the resume device out of software_resume") Signed-off-by: Vlastimil Babka Reviewed-by: Christoph Hellwig Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- kernel/power/hibernate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index e1b4bfa938dd..2b4a946a6ff5 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1166,7 +1166,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, int error; if (!hibernation_available()) - return 0; + return n; if (len && buf[len-1] == '\n') len--; -- cgit v1.2.3 From 3f3d66ba998fb079c1239430e96e3b138bc63166 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:14 -0500 Subject: ASoC: SoundWire codecs: return error status in probe For some reason the first batch of SoundWire codec drivers squelch errors in the SoundWire probe callback. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 4 +--- sound/soc/codecs/rt5682-sdw.c | 4 +--- sound/soc/codecs/rt700-sdw.c | 4 +--- sound/soc/codecs/rt711-sdw.c | 4 +--- sound/soc/codecs/rt715-sdw.c | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f43520ca3187..a7740549d35c 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -715,9 +715,7 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt1308_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt1308_sdw_init(&slave->dev, regmap, slave); } static int rt1308_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 4968a8c0064d..7d53dd62ce17 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -674,9 +674,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return -EINVAL; - rt5682_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt5682_sdw_init(&slave->dev, regmap, slave); } static int rt5682_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 8b28e47775cc..53e7973e0bf9 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt700_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt700_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt700_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 33dced388f9e..530d1ae32c04 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt711_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt711_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt711_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 6db87442b783..d09b3061096d 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -508,9 +508,7 @@ static int rt715_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt715_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt715_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt715_sdw_remove(struct sdw_slave *slave) -- cgit v1.2.3 From 49ae74abc76b2d9be4777e7ac833674fa4749071 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:15 -0500 Subject: ASoC: SoundWire codecs: make regmap cache-only in probe The SoundWire bus may start after the probe where the SoundWire ASoC components are registered. This creates a time window where the card can be created and the registers be accessed. As discussed on the mailing list, we can't really control when codecs are enumerated and initialized, but we can make sure the access to the codecs is cached until the hardware is accessible. This patch configures regcache_cache_only() with a 'true' parameter in the probe function, and a 'false' parameter in the io_init routine. The rt5682 is handled through a different patch due to its specific cache handling. Link: https://lore.kernel.org/alsa-devel/20230503144102.242240-1-krzysztof.kozlowski@linaro.org/ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98363.c | 7 ++++--- sound/soc/codecs/max98373-sdw.c | 7 ++++--- sound/soc/codecs/rt1308-sdw.c | 7 ++++--- sound/soc/codecs/rt1316-sdw.c | 4 +++- sound/soc/codecs/rt1318-sdw.c | 4 +++- sound/soc/codecs/rt700.c | 7 ++++--- sound/soc/codecs/rt711-sdca.c | 8 ++++++-- sound/soc/codecs/rt711.c | 7 ++++--- sound/soc/codecs/rt712-sdca-dmic.c | 7 +++++-- sound/soc/codecs/rt712-sdca.c | 7 +++++-- sound/soc/codecs/rt715-sdca.c | 7 +++++++ sound/soc/codecs/rt715.c | 4 ++++ 12 files changed, 53 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index b5c69bba0e48..80a1cb482183 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -160,10 +160,9 @@ static int max98363_io_init(struct sdw_slave *slave) struct max98363_priv *max98363 = dev_get_drvdata(dev); int ret, reg; - if (max98363->first_hw_init) { - regcache_cache_only(max98363->regmap, false); + regcache_cache_only(max98363->regmap, false); + if (max98363->first_hw_init) regcache_cache_bypass(max98363->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -409,6 +408,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) max98363->regmap = regmap; max98363->slave = slave; + regcache_cache_only(max98363->regmap, true); + max98363->hw_init = false; max98363->first_hw_init = false; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index df92242af960..92d2b872f9f8 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -361,10 +361,9 @@ static int max98373_io_init(struct sdw_slave *slave) struct device *dev = &slave->dev; struct max98373_priv *max98373 = dev_get_drvdata(dev); - if (max98373->first_hw_init) { - regcache_cache_only(max98373->regmap, false); + regcache_cache_only(max98373->regmap, false); + if (max98373->first_hw_init) regcache_cache_bypass(max98373->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -753,6 +752,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) max98373->regmap = regmap; max98373->slave = slave; + regcache_cache_only(max98373->regmap, true); + max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg); max98373->cache = devm_kcalloc(dev, max98373->cache_num, sizeof(*max98373->cache), diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index a7740549d35c..2c4e5330c2df 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -218,10 +218,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) if (rt1308->hw_init) return 0; - if (rt1308->first_hw_init) { - regcache_cache_only(rt1308->regmap, false); + regcache_cache_only(rt1308->regmap, false); + if (rt1308->first_hw_init) regcache_cache_bypass(rt1308->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -688,6 +687,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, rt1308->sdw_slave = slave; rt1308->regmap = regmap; + regcache_cache_only(rt1308->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 10a53c8d4874..57abbe2de7cf 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -272,8 +272,8 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) if (rt1316->hw_init) return 0; + regcache_cache_only(rt1316->regmap, false); if (rt1316->first_hw_init) { - regcache_cache_only(rt1316->regmap, false); regcache_cache_bypass(rt1316->regmap, true); } else { /* @@ -674,6 +674,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, rt1316->sdw_slave = slave; rt1316->regmap = regmap; + regcache_cache_only(rt1316->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 16d750102c8c..d7803342f5c2 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -408,8 +408,8 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) if (rt1318->hw_init) return 0; + regcache_cache_only(rt1318->regmap, false); if (rt1318->first_hw_init) { - regcache_cache_only(rt1318->regmap, false); regcache_cache_bypass(rt1318->regmap, true); } else { /* @@ -752,6 +752,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, rt1318->sdw_slave = slave; rt1318->regmap = regmap; + regcache_cache_only(rt1318->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index a04b9246256b..b774349dfdae 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1099,6 +1099,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, rt700->sdw_regmap = sdw_regmap; rt700->regmap = regmap; + regcache_cache_only(rt700->regmap, true); + mutex_init(&rt700->disable_irq_lock); INIT_DELAYED_WORK(&rt700->jack_detect_work, @@ -1132,10 +1134,9 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hw_init) return 0; - if (rt700->first_hw_init) { - regcache_cache_only(rt700->regmap, false); + regcache_cache_only(rt700->regmap, false); + if (rt700->first_hw_init) regcache_cache_bypass(rt700->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 07640d2f6e56..bd0f5e05874b 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1406,6 +1406,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + regcache_cache_only(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1500,10 +1503,11 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; + regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->mbq_regmap, false); + if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); regcache_cache_bypass(rt711->regmap, true); - regcache_cache_only(rt711->mbq_regmap, false); regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index af53cbcc7bf2..0ca955e2f4e7 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1183,6 +1183,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + regcache_cache_only(rt711->regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1219,10 +1221,9 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; - if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->regmap, false); + if (rt711->first_hw_init) regcache_cache_bypass(rt711->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 869cc7bfd178..0102bad0b66a 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -182,10 +182,10 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* @@ -777,6 +777,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 89d245655ca4..88f6c895722e 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -1183,6 +1183,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + mutex_init(&rt712->calibrate_mutex); mutex_init(&rt712->disable_irq_lock); @@ -1224,10 +1227,10 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index b989f907784b..176340a43446 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -977,6 +977,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, rt715->regmap = regmap; rt715->mbq_regmap = mbq_regmap; rt715->hw_sdw_ver = slave->id.sdw_version; + + regcache_cache_only(rt715->regmap, true); + regcache_cache_only(rt715->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1000,6 +1004,9 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + regcache_cache_only(rt715->mbq_regmap, false); + /* * PM runtime is only enabled when a Slave reports as Attached */ diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 6c2e165dd621..1bd2fe8aa625 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -984,6 +984,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, rt715->regmap = regmap; rt715->sdw_regmap = sdw_regmap; + regcache_cache_only(rt715->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1006,6 +1008,8 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + /* * PM runtime is only enabled when a Slave reports as Attached */ -- cgit v1.2.3 From 6ab18105029ca3d739dd4c5c18638c7c6d568bbb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:16 -0500 Subject: ASoC: rt5682-sdw: make regmap cache-only in probe The RT5682 needs specific attention: there are two regmap in rt5682_priv struct, one is sdw_regmap which is for IO transfer, and the other is used for registers control. We need to set both regmaps when we set cache only. Because if we set rt5682->sdw_regmap only, rt5682->regmap won't set/get the right value when it call regmap_write/read(rt5682->sdw_regmap, ...). If we set rt5682->regmap only, regmap_write(rt5682->sdw_regmap, ...) is used in rt5682_clock_config which will be called by the ..bus_config ops. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230802153629.53576-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 7d53dd62ce17..6726458cf329 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -322,6 +322,9 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, return ret; } + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -352,6 +355,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) if (rt5682->hw_init) return 0; + regcache_cache_only(rt5682->sdw_regmap, false); + regcache_cache_only(rt5682->regmap, false); + if (rt5682->first_hw_init) + regcache_cache_bypass(rt5682->regmap, true); + /* * PM runtime is only enabled when a Slave reports as Attached */ @@ -371,11 +379,6 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); - if (rt5682->first_hw_init) { - regcache_cache_only(rt5682->regmap, false); - regcache_cache_bypass(rt5682->regmap, true); - } - while (loop > 0) { regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val); if (val == DEVICE_ID) @@ -705,6 +708,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) cancel_delayed_work_sync(&rt5682->jack_detect_work); + regcache_cache_only(rt5682->sdw_regmap, true); regcache_cache_only(rt5682->regmap, true); regcache_mark_dirty(rt5682->regmap); @@ -769,6 +773,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) regmap_sync: slave->unattach_request = 0; + regcache_cache_only(rt5682->sdw_regmap, false); regcache_cache_only(rt5682->regmap, false); regcache_sync(rt5682->regmap); -- cgit v1.2.3 From a8590dd73d9f7fd955ac24a8e210d0721d5c10af Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:17 -0500 Subject: ASoC: rt711: enable pm_runtime in probe, keep status as 'suspended' In stress cases involving module insertion/removal followed by playback/capture, it can happen that capture/playback is started before the codec enumeration completes. The codec driver registers its components with the ASoC framework during the probe stage, so there is currently no way for the card creation to wait for the codec enumeration/initialization to complete. In addition, when the capture/playback starts, the ASoC framework uses pm_runtime_get_sync() to properly refcount and power-manage devices. This is problematic in the SoundWire case because pm_runtime is enabled during the enumeration/initialization stage, so pm_runtime_get_sync() will return -EACCESS which is ignored. Additional errors will happen when setting the pm_runtime status as 'active' because the parent is not properly resumed, resulting in an error such as: "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active" This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdw.c | 3 +-- sound/soc/codecs/rt711.c | 40 +++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 530d1ae32c04..3f5773310ae8 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -466,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave) cancel_work_sync(&rt711->calibration_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 0ca955e2f4e7..66eaed13b0d6 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component) rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1206,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt711, rt711_dai, ARRAY_SIZE(rt711_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1226,22 +1250,12 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt711->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt711->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt711->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); rt711_reset(rt711->regmap); -- cgit v1.2.3 From 0c321fb857707ef68ffdb4f9672beb664e6679cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:18 -0500 Subject: ASoC: rt711-sdca: enable pm_runtime in probe, keep status as 'suspended' In stress cases involving module insertion/removal followed by playback/capture, it can happen that capture/playback is started before the codec enumeration completes. The codec driver registers its components with the ASoC framework during the probe stage, so there is currently no way for the card creation to wait for the codec enumeration/initialization to complete. In addition, when the capture/playback starts, the ASoC framework uses pm_runtime_get_sync() to properly refcount and power-manage devices. This is problematic in the SoundWire case because pm_runtime is enabled during the enumeration/initialization stage, so pm_runtime_get_sync() will return -EACCESS which is ignored. Additional errors will happen when setting the pm_runtime status as 'active' because the parent is not properly resumed, resulting in an error such as: "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active" This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca-sdw.c | 3 +-- sound/soc/codecs/rt711-sdca.c | 40 +++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 23f23f714b39..935e597022d3 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt711->jack_btn_check_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index bd0f5e05874b..447154cb6010 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component) rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1434,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711_sdca_dai, ARRAY_SIZE(rt711_sdca_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711) @@ -1511,20 +1536,11 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); -- cgit v1.2.3 From 6b8f8c5e6ffbd431d6cf40584dc8d3027f7e99b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:19 -0500 Subject: ASoC: rt700: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt700-sdw.c | 3 +-- sound/soc/codecs/rt700.c | 39 ++++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 53e7973e0bf9..52c33d56b143 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -464,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt700->jack_btn_check_work); } - if (rt700->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index b774349dfdae..0ebf344a1b60 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, rt700->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component) rt700->component = component; + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1119,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt700, rt700_dai, ARRAY_SIZE(rt700_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ dev_dbg(&slave->dev, "%s\n", __func__); - return ret; + return 0; } int rt700_io_init(struct device *dev, struct sdw_slave *slave) @@ -1141,20 +1164,10 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt700->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - - /* update count of parent 'active' children */ + if (!rt700->first_hw_init) + /* PM runtime status is marked as 'active' only when a Slave reports as Attached */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* reset */ -- cgit v1.2.3 From f3da2ed110e2884b29151313eee52947b786e1a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:20 -0500 Subject: ASoC: rt1712-sdca: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 3 +-- sound/soc/codecs/rt712-sdca.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 6bc50396a0f6..6b644a89c589 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt712->jack_btn_check_work); } - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt712->calibrate_mutex); mutex_destroy(&rt712->disable_irq_lock); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 88f6c895722e..7077ff6ba1f4 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, rt712->hs_jack = hs_jack; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component) rt712_sdca_parse_dt(rt712, &rt712->slave->dev); rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1210,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, else ret = devm_snd_soc_register_component(dev, &soc_sdca_dev_rt712, rt712_sdca_dai, 1); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) @@ -1234,20 +1257,11 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); -- cgit v1.2.3 From 8d890ecef1ef6e2e81f1709d54f6843846cfd15f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:21 -0500 Subject: ASoC: rt712-sdca-dmic: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-dmic.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 0102bad0b66a..ba08d03e717c 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -189,20 +189,11 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component) rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -794,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } @@ -957,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave, static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave) { - struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev); - - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 279be5919560d9f3afea1940bfd261297eecfa0c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:22 -0500 Subject: ASoC: rt715: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdw.c | 5 +---- sound/soc/codecs/rt715.c | 37 ++++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index d09b3061096d..21f37babd148 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -513,10 +513,7 @@ static int rt715_sdw_probe(struct sdw_slave *slave, static int rt715_sdw_remove(struct sdw_slave *slave) { - struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 1bd2fe8aa625..79416bb48814 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -740,8 +740,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component, static int rt715_probe(struct snd_soc_component *component) { + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -997,8 +1001,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt715, rt715_dai, ARRAY_SIZE(rt715_dai)); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } int rt715_io_init(struct device *dev, struct sdw_slave *slave) @@ -1011,22 +1032,12 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_only(rt715->regmap, false); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt715->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt715->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* Mute nid=08h/09h */ -- cgit v1.2.3 From e4a3b8cf40713d6511391de3286ccba38998756b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:23 -0500 Subject: ASoC: rt715-sdca: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdca-sdw.c | 5 +---- sound/soc/codecs/rt715-sdca.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index df10916bab46..ab54a67a27eb 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, static int rt715_sdca_sdw_remove(struct sdw_slave *slave) { - struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 176340a43446..9fa96fd83d4a 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { static int rt715_sdca_probe(struct snd_soc_component *component) { + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -992,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, &soc_codec_dev_rt715_sdca, rt715_sdca_dai, ARRAY_SIZE(rt715_sdca_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1008,21 +1031,12 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_only(rt715->mbq_regmap, false); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ if (!rt715->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - rt715->first_hw_init = true; } -- cgit v1.2.3 From 1772552eb304f3229309f66e2762e835955e2307 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:24 -0500 Subject: ASoC: rt1308-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 2c4e5330c2df..c98cd7abef6a 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -223,22 +223,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1308->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt1308->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt1308->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* sw reset */ @@ -625,6 +615,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component) rt1308->component = component; rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev); + if (!rt1308->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -700,10 +693,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1308, rt1308_sdw_dai, ARRAY_SIZE(rt1308_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1308_sdw_probe(struct sdw_slave *slave, @@ -721,10 +731,7 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, static int rt1308_sdw_remove(struct sdw_slave *slave) { - struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); - - if (rt1308->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 64bae6732b2d3364ce4954015c84b4959f7d6e0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:25 -0500 Subject: ASoC: rt1316-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 57abbe2de7cf..47511f70119a 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -277,20 +277,11 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1316->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -607,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component) rt1316->component = component; rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev); + if (!rt1316->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -687,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1316, rt1316_sdw_dai, ARRAY_SIZE(rt1316_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1316_sdw_probe(struct sdw_slave *slave, @@ -708,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, static int rt1316_sdw_remove(struct sdw_slave *slave) { - struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); - - if (rt1316->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From df93dfa2b4d0f0e2ac2f73f78582a3830659d00e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:26 -0500 Subject: ASoC: rt1318-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1318-sdw.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index d7803342f5c2..ff364bde4a08 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -413,20 +413,10 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1318->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component) rt1318->component = component; + if (!rt1318->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret); if (ret < 0 && ret != -EACCES) @@ -765,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1318, rt1318_sdw_dai, ARRAY_SIZE(rt1318_sdw_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -786,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave, static int rt1318_sdw_remove(struct sdw_slave *slave) { - struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); - - if (rt1318->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 4af11e11defc200439a75a7957b03f3da37e46b2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:27 -0500 Subject: ASoC: rt5682-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 37 ++++++++++++++++++++++--------------- sound/soc/codecs/rt5682.c | 3 +++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 6726458cf329..dfb702d1b3d4 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -339,7 +339,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, ret = devm_snd_soc_register_component(dev, &rt5682_soc_component_dev, rt5682_dai, ARRAY_SIZE(rt5682_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -361,22 +379,12 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt5682->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt5682->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt5682->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); while (loop > 0) { @@ -687,8 +695,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) if (rt5682->hw_init) cancel_delayed_work_sync(&rt5682->jack_detect_work); - if (rt5682->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 5d992543b791..694c581070d9 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1017,6 +1017,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, rt5682->hs_jack = hs_jack; + if (rt5682->is_sdw && !rt5682->first_hw_init) + return 0; + if (!hs_jack) { regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); -- cgit v1.2.3 From d6ce285641cfb506b6942818e06270fb091b8fe3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:28 -0500 Subject: ASoC: max98363: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98363.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 80a1cb482183..9e3873e56e6d 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -165,22 +165,12 @@ static int max98363_io_init(struct sdw_slave *slave) regcache_cache_bypass(max98363->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98363->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98363->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, ®); @@ -417,10 +407,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363, max98363_dai, ARRAY_SIZE(max98363_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + return 0; } static int max98363_sdw_probe(struct sdw_slave *slave, -- cgit v1.2.3 From b48f324f89ab8ee62c3448ef19445a1b292e02d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:29 -0500 Subject: ASoC: max98373-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-sdw.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 92d2b872f9f8..b5cb951af570 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -366,22 +366,12 @@ static int max98373_io_init(struct sdw_slave *slave) regcache_cache_bypass(max98373->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98373->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98373->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); /* Software Reset */ @@ -774,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw, max98373_sdw_dai, ARRAY_SIZE(max98373_sdw_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } static int max98373_update_status(struct sdw_slave *slave, @@ -835,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave, static int max98373_sdw_remove(struct sdw_slave *slave) { - struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev); - - if (max98373->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 5532a1cfedda10ec0c5e9edbb8089e6165b532fe Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:11 +0300 Subject: ASoC: amd: acp-da7219-max98357a: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-2-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 41 +++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 7464ca2b596c..9e3133bec2b1 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -28,6 +28,21 @@ #define RT5682_PLL_FREQ (48000 * 512) static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; static struct clk *rt5682_dai_wclk; @@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(da7219_dai_bclk)) return PTR_ERR(da7219_dai_bclk); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(rt5682_dai_bclk)) return PTR_ERR(rt5682_dai_bclk); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { static const struct snd_soc_dapm_widget cz_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), }; @@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = { static const struct snd_kcontrol_new cz_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), }; -- cgit v1.2.3 From 596c92fb77a0402b3f2d3ebd36ef6c6aec45faf5 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:12 +0300 Subject: ASoC: amd: acp-rt5645: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-3-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-rt5645.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c index 532aa98a2241..c8ed1e0b1ccd 100644 --- a/sound/soc/amd/acp-rt5645.c +++ b/sound/soc/amd/acp-rt5645.c @@ -42,6 +42,16 @@ #define CZ_PLAT_CLK 24000000 static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int cz_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -76,11 +86,13 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd) codec = asoc_rtd_to_codec(rtd, 0)->component; card = rtd->card; - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; -- cgit v1.2.3 From 7ac3404c2e21ff6b717fd9ac2f7b352e0149f7bd Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:13 +0300 Subject: ASoC: amd: acp: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682, RT5682s, NAU8825 and NAU8821 codecs used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols and add the necessary widgets. Split the jack and pin structs per-codec to accommodate for per-codec differences. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-4-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 226 +++++++++++++++++++++++++++++------- 1 file changed, 182 insertions(+), 44 deletions(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index ff5cbc4a6427..f3abaa182fbb 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -28,7 +28,6 @@ #include "../../codecs/nau8821.h" #include "acp-mach.h" -static struct snd_soc_jack vg_headset; #define PCO_PLAT_CLK 48000000 #define RT5682_PLL_FREQ (48000 * 512) #define DUAL_CHANNEL 2 @@ -52,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_quirk_table); -static struct snd_soc_jack pco_jack; - static const unsigned int channels[] = { DUAL_CHANNEL, }; @@ -87,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata, SND_SOC_DAILINK_DEF(rt5682, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); +static struct snd_soc_jack rt5682_jack; +static struct snd_soc_jack_pin rt5682_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -110,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, + ARRAY_SIZE(rt5682_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682_controls, + ARRAY_SIZE(rt5682_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682_jack, + rt5682_jack_pins, + ARRAY_SIZE(rt5682_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -275,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = { SND_SOC_DAILINK_DEF(rt5682s, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1"))); +static struct snd_soc_jack rt5682s_jack; +static struct snd_soc_jack_pin rt5682s_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682s_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682s_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -299,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); } - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets, + ARRAY_SIZE(rt5682s_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682s_controls, + ARRAY_SIZE(rt5682s_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682s_jack, + rt5682s_jack_pins, + ARRAY_SIZE(rt5682s_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -762,6 +835,28 @@ static const struct snd_soc_ops acp_max98388_ops = { SND_SOC_DAILINK_DEF(nau8825, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); +static struct snd_soc_jack nau8825_jack; +static struct snd_soc_jack_pin nau8825_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8825_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget nau8825_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route nau8825_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -780,22 +875,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != NAU8825) return -EINVAL; - ret = snd_soc_card_jack_new(card, "Headset Jack", + ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets, + ARRAY_SIZE(nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8825_controls, + ARRAY_SIZE(nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + &nau8825_jack, + nau8825_jack_pins, + ARRAY_SIZE(nau8825_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -921,8 +1032,25 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return ret; } +static struct snd_soc_jack nau8821_jack; +static struct snd_soc_jack_pin nau8821_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8821_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget nau8821_widgets[] = { - SND_SOC_DAPM_HP("Headphone jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, @@ -932,12 +1060,12 @@ static const struct snd_soc_dapm_widget nau8821_widgets[] = { static const struct snd_soc_dapm_route nau8821_audio_route[] = { /* HP jack connectors - unknown if we have jack detection */ - { "Headphone jack", NULL, "HPOL" }, - { "Headphone jack", NULL, "HPOR" }, + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, { "MICL", NULL, "Headset Mic" }, { "MICR", NULL, "Headset Mic" }, { "DMIC", NULL, "Int Mic" }, - { "Headphone jack", NULL, "Platform Clock" }, + { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Int Mic", NULL, "Platform Clock" }, }; @@ -966,21 +1094,31 @@ static int acp_8821_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &vg_headset); + ret = snd_soc_add_card_controls(card, nau8821_controls, + ARRAY_SIZE(nau8821_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &nau8821_jack, + nau8821_jack_pins, + ARRAY_SIZE(nau8821_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - nau8821_enable_jack_detect(component, &vg_headset); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + nau8821_enable_jack_detect(component, &nau8821_jack); return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route, ARRAY_SIZE(nau8821_audio_route)); -- cgit v1.2.3 From 00c7ee820895c9563b7780f84f1b9420cbfbe6c7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:14 +0300 Subject: ASoC: amd: acp3x-rt5682-max9836: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682, RT1015 and RT1015p codecs used here can detect Headphone and Headset Mic connections. Expose the former two to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-5-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp3x-rt5682-max9836.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 0543dda75b99..3bf7e1e83c36 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -28,6 +28,17 @@ #define DUAL_CHANNEL 2 static struct snd_soc_jack pco_jack; +static struct snd_soc_jack_pin pco_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct clk *rt5682_dai_wclk; static struct clk *rt5682_dai_bclk; static struct gpio_desc *dmic_sel; @@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pco_jack, + pco_jack_pins, + ARRAY_SIZE(pco_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; -- cgit v1.2.3 From c699fc46f45bab70a831a56e95d6f6c6e51ac7be Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:15 +0300 Subject: ASoC: Intel: avs: da7219: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-6-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/da7219.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 964a763732ab..85014d98f7e8 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -22,6 +22,7 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), }; @@ -68,6 +70,22 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) @@ -75,7 +93,9 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; struct snd_soc_jack *jack; + int num_pins; int clk_freq; int ret; @@ -91,14 +111,20 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } + num_pins = ARRAY_SIZE(card_headset_pins); + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + jack, pins, num_pins); if (ret) { dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From 92d7071f751a863fe22aaf8cfdd94f96749e0aa5 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:16 +0300 Subject: ASoC: Intel: bxt_da7219_max98357a: Map missing Line Out jack kcontrol Commit bbdd4ea2190b4 ("ASoC: Intel: bxt_da7219_max98357a: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-7-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c593995facaa..cbfff466c5c8 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -90,6 +90,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new broxton_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_kcontrol_new max98357a_controls[] = { @@ -104,6 +105,7 @@ static const struct snd_kcontrol_new max98390_controls[] = { static const struct snd_soc_dapm_widget broxton_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -150,6 +152,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static const struct snd_soc_dapm_route max98357a_routes[] = { @@ -194,6 +197,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.3 From 4e06382c0d275fa1e365ca2ee9b2286b7c49b07f Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:17 +0300 Subject: ASoC: Intel: bytcr_wm5102: Map missing Line Out jack kcontrol Commit ecd77d494ec9 ("ASoC: Intel: bytcr_wm5102: Add jack detect support") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The WM5102 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-8-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_wm5102.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index f2382d4cb76f..5c9e06ed1a53 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -144,6 +145,7 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = { {"Headset Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"}, + {"Line Out", NULL, "Platform Clock"}, {"Speaker", NULL, "SPKOUTLP"}, {"Speaker", NULL, "SPKOUTLN"}, @@ -177,6 +179,7 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static struct snd_soc_jack_pin byt_wm5102_pins[] = { @@ -188,6 +191,10 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) -- cgit v1.2.3 From da09176f1f04baae467c97a4dc8b6d9fa5cd11b8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:18 +0300 Subject: ASoC: Intel: kbl_da7219_max98357a: Map missing Line Out jack kcontrol Commit c2065d43ae85 ("ASoC: Intel: kbl_da7219_max98357a: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-9-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 18365ce6bcba..97149513076f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -83,12 +83,14 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -107,6 +109,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -147,6 +153,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.3 From 2830bfdbe90b0bf6170f88ca0803fa72e1b1e506 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:19 +0300 Subject: ASoC: Intel: kbl_da7219_max98927: Map missing Line Out jack kcontrol Commit b9f53b9fc14e ("ASoC: Intel: kbl_da7219_max98927: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-10-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98927.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index ad4223fee0c5..a1f8234c77bd 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -102,6 +102,7 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { @@ -109,6 +110,7 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -127,6 +129,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_MICROPHONE, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -182,6 +188,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 7265089ade245d062fe8f9938261656ff2a49633 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:20 +0300 Subject: ASoC: Intel: sof_da7219_max98373: Map missing Line Out jack kcontrol Commit 2913bb1f6830 ("ASoC: Intel: sof_da7219_max98373: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-11-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_da7219_max98373.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index 740aa11cb019..bbd47e7e4343 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -65,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), }; @@ -72,6 +73,7 @@ static const struct snd_kcontrol_new controls[] = { static const struct snd_kcontrol_new m98360a_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Spk"), }; @@ -79,6 +81,7 @@ static const struct snd_kcontrol_new m98360a_controls[] = { static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), @@ -98,6 +101,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -110,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static const struct snd_soc_dapm_widget max98360a_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Spk", NULL), @@ -128,6 +133,7 @@ static const struct snd_soc_dapm_route max98360a_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, {"Spk", NULL, "Speaker"}, @@ -144,6 +150,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_jack headset; -- cgit v1.2.3 From 105e84586bfcbe8e48e386936899c4eb8c00be71 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:21 +0300 Subject: ASoC: imx-es8328: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. It seems to have a single detection GPIO pin used to report everything as a Headset. But it has widgets for Headphone and Mic Jack, so expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-12-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 85bd36fb68a2..6f0d031c1d5f 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -37,6 +37,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = { }; static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) { @@ -46,9 +56,11 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) /* Headphone jack detection */ if (gpio_is_valid(data->jack_gpio)) { - ret = snd_soc_card_jack_new(rtd->card, "Headphone", - SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; @@ -68,6 +80,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), }; +static const struct snd_kcontrol_new imx_es8328_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; + static int imx_es8328_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -183,6 +200,8 @@ static int imx_es8328_probe(struct platform_device *pdev) data->card.dev = dev; data->card.dapm_widgets = imx_es8328_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + data->card.controls = imx_es8328_controls; + data->card.num_controls = ARRAY_SIZE(imx_es8328_controls); ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) { dev_err(dev, "Unable to parse card name\n"); -- cgit v1.2.3 From 73864428ba983bc35e1efabc2e3ec04c6d87c67c Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:22 +0300 Subject: ASoC: mediatek: mt8173-max98090: Configure jack as a Headset jack This driver has correctly mapped jack kcontrols for Headphone and Headset Mic. However, it is configuring the jack to only care about Headphone events. The MAX98090 codec used here can detect both connections, so configure the jack as such. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-13-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index c2b0619b6158..bfb2094758ff 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -70,7 +70,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; /* enable jack detection */ - ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE, + ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET, &mt8173_max98090_jack, mt8173_max98090_jack_pins, ARRAY_SIZE(mt8173_max98090_jack_pins)); -- cgit v1.2.3 From 87eb19815fa53220602fa40b77f7e3504bf6b476 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:23 +0300 Subject: ASoC: mediatek: mt8173-rt5650-rt5514: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-14-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index f803f121659d..e502cd1670ba 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -40,6 +40,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -82,11 +93,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) RT5645_CLK_SEL_I2S1_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5514_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5514_jack, + mt8173_rt5650_rt5514_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 8badca99caf0cc843341e3ffa87d24f9caa206c9 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:24 +0300 Subject: ASoC: mediatek: mt8173-rt5650-rt5676: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-15-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 8794720cea3a..ffb094284bfb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -44,6 +44,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -95,11 +106,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime) RT5677_CLK_SEL_I2S2_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5676_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5676_jack, + mt8173_rt5650_rt5676_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 0ef5533f7b54419f5b108d6004f56c6de78f026d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:25 +0300 Subject: ASoC: mediatek: mt8173-rt5650: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-16-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 3ece4b5eaca2..18cf84bb25c7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -54,6 +54,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -128,11 +139,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) } /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_jack, + mt8173_rt5650_jack_pins, + ARRAY_SIZE(mt8173_rt5650_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 9c7388baa2053f333dc524814be4d95f0c2c8ae7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:26 +0300 Subject: ASoC: mediatek: mt8183-da7219-max98357: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-17-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 43 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 87bb04846991..701fbcc0f2c9 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -29,6 +29,21 @@ struct mt8183_da7219_max98357_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; +static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -572,13 +587,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_LINEOUT, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_LINEOUT, + &priv->headset_jack, + mt8183_da7219_max98357_jack_pins, + ARRAY_SIZE(mt8183_da7219_max98357_jack_pins)); if (ret) return ret; @@ -609,12 +626,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_SPK("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; @@ -657,14 +680,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; -- cgit v1.2.3 From 09a22368bb87a90a447d901e7f5bf2037f321769 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:27 +0300 Subject: ASoC: mediatek: mt8183-mt6358-ts3a227-max98357: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The TS3A227 component used here can detect Headphones and Headset Mic connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-18-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 53 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index ce9aedde7e1e..850f4d949d97 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -592,11 +592,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { }, }; +static const +struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const +struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .name = "mt8183_mt6358_ts3a227_max98357", .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { @@ -604,6 +631,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = { @@ -624,6 +655,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = { .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), .codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf, .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { @@ -631,6 +666,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static int @@ -641,12 +680,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &priv->headset_jack, + mt8183_mt6358_ts3a227_max98357_jack_pins, + ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins)); if (ret) return ret; -- cgit v1.2.3 From 26de9cc1b96eecfe9fb9c672272665e97c3cdc59 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:28 +0300 Subject: ASoC: mediatek: mt8186-mt6366-da7219-max98357: Map missing jack kcontrols Commit 8e9867486806 ("ASoC: mediatek: mt8186-da7219: Expose individual headset jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-19-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 0432f9d89020..aa8e00bba19b 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -46,6 +46,10 @@ static struct snd_soc_jack_pin mt8186_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { @@ -964,6 +968,7 @@ mt8186_mt6366_da7219_max98357_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -996,6 +1001,7 @@ mt8186_mt6366_da7219_max98357_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("HDMI1"), }; -- cgit v1.2.3 From 45bda58af84ffd5c951267f848c8dc10ea485c06 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:29 +0300 Subject: ASoC: qcom: apq8016_sbc: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. It seems to support detecting Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-20-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index e54b8961112f..6de533d45e7d 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -44,6 +44,17 @@ struct apq8016_sbc_data { #define DEFAULT_MCLK_RATE 9600000 #define MI2S_BCLK_RATE 1536000 +static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) { struct snd_soc_dai *codec_dai; @@ -90,13 +101,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) if (!pdata->jack_setup) { struct snd_jack *jack; - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4, + &pdata->jack, + apq8016_sbc_jack_pins, + ARRAY_SIZE(apq8016_sbc_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -255,8 +268,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card) } } -static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { +static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; +static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("Handset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Secondary Mic", NULL), @@ -285,6 +304,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dapm_widgets = apq8016_sbc_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); + card->controls = apq8016_sbc_snd_controls; + card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls); ret = qcom_snd_parse_of(card); if (ret) -- cgit v1.2.3 From 883bfefca437c9061686fa8d092d5a8fa04d06c8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:30 +0300 Subject: ASoC: qcom: sc7180: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682 and RT5682s codecs used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-21-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index f5f7c64b23a2..57c5f35dfcc5 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -42,6 +42,17 @@ static void sc7180_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7180_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -51,13 +62,14 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) struct snd_jack *jack; int rval; - rval = snd_soc_card_jack_new( - card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->hs_jack, + sc7180_jack_pins, + ARRAY_SIZE(sc7180_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -297,6 +309,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7180_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = { SND_SOC_DAPM_MIC("DMIC", NULL), }; @@ -320,6 +337,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = { SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control), }; +static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { {"Dmic Mux", "Front Mic", "DMIC"}, {"Dmic Mux", "Rear Mic", "DMIC"}, @@ -348,10 +370,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) card->dev = dev; card->dapm_widgets = sc7180_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); + card->controls = sc7180_snd_controls; + card->num_controls = ARRAY_SIZE(sc7180_snd_controls); if (of_property_read_bool(dev->of_node, "dmic-gpios")) { card->dapm_widgets = sc7180_snd_dual_mic_widgets, card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets), + card->controls = sc7180_snd_dual_mic_controls, + card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls), card->dapm_routes = sc7180_snd_dual_mic_audio_route, card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route), data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); -- cgit v1.2.3 From 4ab959e5a11624805983909d18ca7f653bab748c Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:31 +0300 Subject: ASoC: qcom: sc7280: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682 and RT5682s codecs used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-22-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7280.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index 787dd49e03f6..43010e4e2242 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -43,6 +43,17 @@ static void sc7280_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7280_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -54,13 +65,15 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) int rval, i; if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &pdata->hs_jack, + sc7280_jack_pins, + ARRAY_SIZE(sc7280_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -361,6 +374,11 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7280_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -396,6 +414,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev) card->dapm_widgets = sc7280_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); + card->controls = sc7280_snd_controls; + card->num_controls = ARRAY_SIZE(sc7280_snd_controls); ret = qcom_snd_parse_of(card); if (ret) -- cgit v1.2.3 From 242372d64e5ee39be518672abd7b797d5cd9521b Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:32 +0300 Subject: ASoC: qcom: sdm845: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5663 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-23-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 02612af714a8..29d23fe5dfa2 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -42,6 +42,17 @@ struct sdm845_snd_data { struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; }; +static struct snd_soc_jack_pin sdm845_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, @@ -242,12 +253,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->jack, + sdm845_jack_pins, + ARRAY_SIZE(sdm845_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -539,6 +552,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), }; +static const struct snd_kcontrol_new sdm845_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static void sdm845_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -572,6 +590,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) card->driver_name = DRIVER_NAME; card->dapm_widgets = sdm845_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); + card->controls = sdm845_snd_controls; + card->num_controls = ARRAY_SIZE(sdm845_snd_controls); card->dev = dev; card->owner = THIS_MODULE; dev_set_drvdata(dev, card); -- cgit v1.2.3 From d60e810a0fa83692116293b4b798ab0273668108 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:33 +0300 Subject: ASoC: rk3399-gru-sound: Map missing Line Out jack kcontrol Commit d0508b4f1604 ("ASoC: rk3399_gru_sound: Add DAPM pins, kcontrols for jack detection") maps kcontrols for Headphones and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle insertion events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widget. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-24-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3399_gru_sound.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 5e52e9d60d44..0f704d22d21b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -41,13 +41,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, - + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_LINE("HDMI", NULL), }; @@ -56,6 +60,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Int Mic"), SOC_DAPM_PIN_SWITCH("HDMI"), }; -- cgit v1.2.3 From 24127e5a07a8eac754be50f537df891ebdadf1b8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:34 +0300 Subject: ASoC: rockchip: rockchip_rt5645: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here supports detecting Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-25-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_rt5645.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index e73a342b7953..ef9fdf0386cb 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -22,6 +22,16 @@ #define DRV_NAME "rockchip-snd-rt5645" static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), @@ -103,11 +113,13 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) int ret; /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) { dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); return ret; -- cgit v1.2.3 From 4d87362f017ea16b6035906613a1c29095a6134f Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:35 +0300 Subject: ASoC: samsung: littlemill: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The WM8958 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-26-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/littlemill.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 5d8118e69359..fafadcef234e 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -225,12 +225,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, } static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_HP("Headset Mic", NULL), SND_SOC_DAPM_MIC("AMIC", NULL), SND_SOC_DAPM_MIC("DMIC", NULL), @@ -255,6 +258,16 @@ static const struct snd_soc_dapm_route audio_paths[] = { }; static struct snd_soc_jack littlemill_headset; +static struct snd_soc_jack_pin littlemill_headset_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int littlemill_late_probe(struct snd_soc_card *card) { @@ -281,12 +294,14 @@ static int littlemill_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &littlemill_headset); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &littlemill_headset, + littlemill_headset_pins, + ARRAY_SIZE(littlemill_headset_pins)); if (ret) return ret; -- cgit v1.2.3 From c9d3401844fa6ec6fa924859dca95bac38b1e1ff Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:36 +0300 Subject: ASoC: samsung: lowland: Split Line Out jack kcontrol from Headphone This driver has correctly mapped jack kcontrols for Headphone and Headset Mic. However, it is also mapping Line Out jack detection events to the Headphone kcontrol. The WM5100 codec used here can distinguish Line Out connections from Headphone connections. Decouple the two, expose Line Out to userspace as an independent kcontrol and add the necessary widget. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-27-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/lowland.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 106770be6fc5..a79df871ea13 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -22,12 +22,16 @@ static struct snd_soc_jack lowland_headset; static struct snd_soc_jack_pin lowland_headset_pins[] = { { .pin = "Headphone", - .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, + .mask = SND_JACK_HEADPHONE, }, { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) @@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Main Speaker", NULL), -- cgit v1.2.3 From d27224a45e5457ad89195d92decdd57596253428 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:37 +0300 Subject: ASoC: samsung: midas_wm1811: Map missing jack kcontrols This driver does not map jack pins to kcontrols that PulseAudio/PipeWire need to handle jack detection events. The WM1811 codec used here seems to support detecting Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-28-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 6931b9a45b3e..44b32f5cddca 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -38,6 +38,17 @@ struct midas_priv { struct snd_soc_jack headset_jack; }; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate) { struct snd_soc_card *card = rtd->card; @@ -246,6 +257,7 @@ static const struct snd_kcontrol_new midas_controls[] = { SOC_DAPM_PIN_SWITCH("Main Mic"), SOC_DAPM_PIN_SWITCH("Sub Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("FM In"), }; @@ -261,6 +273,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { SND_SOC_DAPM_LINE("HDMI", NULL), SND_SOC_DAPM_LINE("FM In", midas_fm_set), + SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias), SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias), @@ -305,11 +318,13 @@ static int midas_late_probe(struct snd_soc_card *card) return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, + &priv->headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; -- cgit v1.2.3 From 7136368a2f3fda492d696bdeddf4d2af71fa8b92 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Jul 2023 22:18:24 +0200 Subject: ASoC: dt-bindings: Convert maxim,max98925 to DT schema Convert the Maxim Integrated MAX98925/MAX98926/MAX98927 speaker amplifier bindings to DT schema format. Changes during conversion: 1. Add "sound-dai-cells", already used by DTS. 2. Use "maxim,interleave-mode" instead previous "interleave-mode" and undocumented but used interleave_mode. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730201826.70453-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max9892x.txt | 44 ---------- .../devicetree/bindings/sound/maxim,max98925.yaml | 98 ++++++++++++++++++++++ 2 files changed, 98 insertions(+), 44 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/max9892x.txt create mode 100644 Documentation/devicetree/bindings/sound/maxim,max98925.yaml diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt deleted file mode 100644 index 98cb9ba5b328..000000000000 --- a/Documentation/devicetree/bindings/sound/max9892x.txt +++ /dev/null @@ -1,44 +0,0 @@ -Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier - -This device supports I2C. - -Required properties: - - - compatible : should be one of the following - - "maxim,max98925" - - "maxim,max98926" - - "maxim,max98927" - - - vmon-slot-no : slot number used to send voltage information - or in inteleave mode this will be used as - interleave slot. - MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 - MAX98927 slot range : 0 ~ 15, Default : 0 - - - imon-slot-no : slot number used to send current information - MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 - MAX98927 slot range : 0 ~ 15, Default : 0 - - - interleave-mode : When using two MAX9892X in a system it is - possible to create ADC data that that will - overflow the frame size. Digital Audio Interleave - mode provides a means to output VMON and IMON data - from two devices on a single DOUT line when running - smaller frames sizes such as 32 BCLKS per LRCLK or - 48 BCLKS per LRCLK. - Range : 0 (off), 1 (on), Default : 0 - - - reg : the I2C address of the device for I2C - -Optional properties: - - reset-gpios : GPIO to reset the device - -Example: - -codec: max98927@3a { - compatible = "maxim,max98927"; - vmon-slot-no = <0>; - imon-slot-no = <1>; - interleave-mode = <0>; - reg = <0x3a>; -}; diff --git a/Documentation/devicetree/bindings/sound/maxim,max98925.yaml b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml new file mode 100644 index 000000000000..32fd86204a7a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/maxim,max98925.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX98925/MAX98926/MAX98927 speaker amplifier + +maintainers: + - Ryan Lee + +properties: + compatible: + enum: + - maxim,max98925 + - maxim,max98926 + - maxim,max98927 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + vmon-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 30 + default: 0 + description: + Slot number used to send voltage information or in inteleave mode this + will be used as interleave slot. + + imon-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 30 + default: 0 + description: + Slot number used to send current information. + + maxim,interleave-mode: + type: boolean + description: + When using two MAX9892X in a system it is possible to create ADC data + that will overflow the frame size. When enabled, the Digital Audio + Interleave mode provides a means to output VMON and IMON data from two + devices on a single DOUT line when running smaller frames sizes such as + 32 BCLKS per LRCLK or 48 BCLKS per LRCLK. + +required: + - compatible + - reg + +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - maxim,max98927 + then: + properties: + vmon-slot-no: + minimum: 0 + maximum: 15 + + imon-slot-no: + minimum: 0 + maximum: 15 + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + #include + audio-codec@3a { + compatible = "maxim,max98927"; + reg = <0x3a>; + #sound-dai-cells = <0>; + + pinctrl-0 = <&speaker_default>; + pinctrl-names = "default"; + + reset-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + + vmon-slot-no = <1>; + imon-slot-no = <0>; + }; + }; -- cgit v1.2.3 From ddef7518e76d832ab9f6d0430ad28cc0e04c083a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Jul 2023 22:18:25 +0200 Subject: ASoC: codecs: max9892x: Unify interleave mode OF property MAX98926 and MAX98927 are quite similar and use the same bindings, although drivers were not implementing them in the same way: MAX98926 has boolean "interleave-mode" but MAX98927 has uint32 "interleave_mode". Unify them under maxim,interleave-mode, already used in other Maxim device. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730201826.70453-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 3 ++- sound/soc/codecs/max98927.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index bdc508e23e59..922ce0dc4e60 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); goto err_out; } - if (of_property_read_bool(i2c->dev.of_node, "interleave-mode")) + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") || + of_property_read_bool(i2c->dev.of_node, "interleave-mode")) max98926->interleave_mode = true; if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 0aaf2e6ae78d..e20aa5b1bce9 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -879,14 +879,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, max98927); /* update interleave mode info */ - if (!of_property_read_u32(i2c->dev.of_node, - "interleave_mode", &value)) { - if (value > 0) - max98927->interleave_mode = true; - else - max98927->interleave_mode = false; - } else - max98927->interleave_mode = false; + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) { + max98927->interleave_mode = true; + } else { + if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", + &value)) + if (value > 0) + max98927->interleave_mode = true; + } /* regmap initialization */ max98927->regmap -- cgit v1.2.3 From 38b288ab454f9aecf7b717974028f57f5243dc5a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Jul 2023 22:18:26 +0200 Subject: ASoC: codecs: max9892x: Reformat to coding style Reformat the code to match Linuxn coding style: re-indent continued lines and stop too-early line wrapping, drop unneeded {} brackets. No functional impact. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730201826.70453-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 341 ++++++++++++++++++-------------------------- 1 file changed, 137 insertions(+), 204 deletions(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index e20aa5b1bce9..776f23d38ac5 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -162,10 +162,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MASK, - mode); + regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MASK, mode); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -178,10 +176,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, - invert); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert); /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -207,36 +203,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) if (!use_pdm) { /* pcm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_FORMAT_MASK, - format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_FORMAT_MASK, + format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 0); } else { /* pdm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 3); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 3); - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + 0); } return 0; } @@ -283,9 +274,9 @@ static int max98927_set_clock(struct max98927_priv *max98927, return -EINVAL; } regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MCLK_MASK, - i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); + MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MCLK_MASK, + i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); } if (!max98927->tdm_mode) { @@ -298,9 +289,8 @@ static int max98927_set_clock(struct max98927_priv *max98927, } regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - value); + MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, value); } return 0; } @@ -333,9 +323,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, max98927->ch_size = snd_pcm_format_width(params_format(params)); - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); dev_dbg(component->dev, "format supported %d", params_format(params)); @@ -375,27 +364,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, goto err; } /* set DAI_SR to correct LRCLK frequency */ - regmap_update_bits(max98927->regmap, - MAX98927_R0023_PCM_SR_SETUP1, - MAX98927_PCM_SR_SET1_SR_MASK, - sampling_rate); - regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_SR_MASK, - sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); + regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1, + MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate); + regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_SR_MASK, + sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); /* set sampling rate of IV */ if (max98927->interleave_mode && sampling_rate > MAX98927_PCM_SR_SET1_SR_16000) regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate - 3); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate - 3); else regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate); return max98927_set_clock(max98927, params); err: return -EINVAL; @@ -420,10 +406,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - bsel); + regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel); /* Channel size configuration */ switch (slot_width) { @@ -442,33 +426,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); /* Rx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - rx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0019_PCM_RX_EN_B, - (rx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + rx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B, + (rx_mask & 0xFF00) >> 8); /* Tx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - (tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + (tx_mask & 0xFF00) >> 8); /* Tx slot Hi-Z configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - ~tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - (~tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + ~tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + (~tx_mask & 0xFF00) >> 8); return 0; } @@ -506,20 +483,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 1); break; case SND_SOC_DAPM_POST_PMD: - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 0); break; default: return 0; @@ -532,8 +505,8 @@ static const char * const max98927_switch_text[] = { static const struct soc_enum dai_sel_enum = SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, - 3, max98927_switch_text); + MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3, + max98927_switch_text); static const struct snd_kcontrol_new max98927_dai_controls = SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); @@ -543,17 +516,17 @@ static const struct snd_kcontrol_new max98927_vi_control = static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN, - 0, 0, max98927_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + 0, 0, max98927_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, - &max98927_dai_controls), + &max98927_dai_controls), SND_SOC_DAPM_OUTPUT("BE_OUT"), SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 0, 0), + MAX98927_R003E_MEAS_EN, 0, 0), SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 1, 0), + MAX98927_R003E_MEAS_EN, 1, 0), SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, - &max98927_vi_control), + &max98927_vi_control), SND_SOC_DAPM_SIGGEN("VMON"), SND_SOC_DAPM_SIGGEN("IMON"), }; @@ -623,20 +596,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit, max98927_current_limit_text); static const struct snd_kcontrol_new max98927_snd_controls[] = { - SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, - 0, 6, 0, - max98927_spk_tlv), + SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0, + max98927_spk_tlv), SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL, - 0, (1<component = component; /* Software Reset */ - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); /* IV default slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - 0x80); - regmap_write(max98927->regmap, - MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, - 0x1); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF); + regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, + 0x80); + regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, + 0x1); /* Set inital volume (+13dB) */ - regmap_write(max98927->regmap, - MAX98927_R0036_AMP_VOL_CTRL, - 0x38); - regmap_write(max98927->regmap, - MAX98927_R003C_SPK_GAIN, - 0x05); + regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38); + regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05); /* Enable DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R0037_AMP_DSP_CFG, - 0x03); + regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03); /* Enable IMON VMON DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R003F_MEAS_DSP_CFG, - 0xF7); + regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7); /* Boost Output Voltage & Current limit */ - regmap_write(max98927->regmap, - MAX98927_R0040_BOOST_CTRL0, - 0x1C); - regmap_write(max98927->regmap, - MAX98927_R0042_BOOST_CTRL1, - 0x3E); + regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C); + regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E); /* Measurement ADC config */ - regmap_write(max98927->regmap, - MAX98927_R0043_MEAS_ADC_CFG, - 0x04); - regmap_write(max98927->regmap, - MAX98927_R0044_MEAS_ADC_BASE_MSB, - 0x00); - regmap_write(max98927->regmap, - MAX98927_R0045_MEAS_ADC_BASE_LSB, - 0x24); + regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04); + regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00); + regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24); /* Brownout Level */ - regmap_write(max98927->regmap, - MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, - 0x06); + regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, + 0x06); /* Envelope Tracking configuration */ - regmap_write(max98927->regmap, - MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, - 0x08); - regmap_write(max98927->regmap, - MAX98927_R0086_ENV_TRACK_CTRL, - 0x01); - regmap_write(max98927->regmap, - MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, - 0x10); + regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, + 0x08); + regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01); + regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, + 0x10); /* voltage, current slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001E_PCM_TX_CH_SRC_A, - (max98927->i_l_slot<v_l_slot)&0xFF); + regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A, + (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF); if (max98927->v_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->v_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->v_l_slot, - 1 << max98927->v_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->v_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->v_l_slot, + 1 << max98927->v_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->v_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->v_l_slot - 8), - 1 << (max98927->v_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->v_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->v_l_slot - 8), + 1 << (max98927->v_l_slot - 8)); } if (max98927->i_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->i_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->i_l_slot, - 1 << max98927->i_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->i_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->i_l_slot, + 1 << max98927->i_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->i_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->i_l_slot - 8), - 1 << (max98927->i_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->i_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->i_l_slot - 8), + 1 << (max98927->i_l_slot - 8)); } /* Set interleave mode */ if (max98927->interleave_mode) regmap_update_bits(max98927->regmap, - MAX98927_R001F_PCM_TX_CH_SRC_B, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK); + MAX98927_R001F_PCM_TX_CH_SRC_B, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK); return 0; } @@ -809,8 +746,8 @@ static int max98927_resume(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); regcache_cache_only(max98927->regmap, false); regcache_sync(max98927->regmap); return 0; @@ -869,9 +806,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) int reg = 0; struct max98927_priv *max98927 = NULL; - max98927 = devm_kzalloc(&i2c->dev, - sizeof(*max98927), GFP_KERNEL); - + max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL); if (!max98927) { ret = -ENOMEM; return ret; @@ -897,9 +832,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); return ret; } - - max98927->reset_gpio - = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH); + + max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(max98927->reset_gpio)) { ret = PTR_ERR(max98927->reset_gpio); return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin"); @@ -912,8 +847,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) } /* Check Revision ID */ - ret = regmap_read(max98927->regmap, - MAX98927_R01FF_REV_ID, ®); + ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID); @@ -938,9 +872,8 @@ static void max98927_i2c_remove(struct i2c_client *i2c) { struct max98927_priv *max98927 = i2c_get_clientdata(i2c); - if (max98927->reset_gpio) { + if (max98927->reset_gpio) gpiod_set_value_cansleep(max98927->reset_gpio, 1); - } } static const struct i2c_device_id max98927_i2c_id[] = { -- cgit v1.2.3 From 1ec6dffdedae4cbbd6e33b1d9be0e5a3dbb31804 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 12:14:21 +0100 Subject: ASoC: jz4740: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the jz4740 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-jz-maple-v1-1-3f745adf96e5@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 7c25acf6ff0d..d1cea93bdb59 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -301,7 +301,7 @@ static const struct regmap_config jz4740_codec_regmap_config = { .reg_defaults = jz4740_codec_reg_defaults, .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int jz4740_codec_probe(struct platform_device *pdev) -- cgit v1.2.3 From 517d52ae5cf75d55970345ece4f6743abdf4620f Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 4 Aug 2023 19:47:47 +0800 Subject: ASoC: dt-bindings: Add schema for "awinic,aw88261" Add the awinic,aw88261 property to the awinic,aw88395.yaml file. Signed-off-by: Weidong Wang Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230804114749.215460-2-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/awinic,aw88395.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml index 35eef7d818a2..4051c2538caf 100644 --- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml +++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml @@ -19,7 +19,9 @@ allOf: properties: compatible: - const: awinic,aw88395 + enum: + - awinic,aw88395 + - awinic,aw88261 reg: maxItems: 1 -- cgit v1.2.3 From 7f4ec77802aa17518990ed954bf536fd3bcf25cb Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 4 Aug 2023 19:47:48 +0800 Subject: ASoC: codecs: Add code for bin parsing compatible with aw88261 Add aw88261 compatible code to the aw88395_lib.c file so that it can parse aw88261's bin file. Signed-off-by: Weidong Wang Link: https://lore.kernel.org/r/20230804114749.215460-3-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395_lib.c | 193 ++++++++++++++++++++++++++++++--- sound/soc/codecs/aw88395/aw88395_reg.h | 1 + 2 files changed, 177 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 05bcf49da857..8ee1baa03269 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -11,6 +11,7 @@ #include #include "aw88395_lib.h" #include "aw88395_device.h" +#include "aw88395_reg.h" #define AW88395_CRC8_POLYNOMIAL 0x8C DECLARE_CRC8_TABLE(aw_crc8_table); @@ -429,6 +430,53 @@ parse_bin_failed: return ret; } +static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + struct aw_bin *aw_bin; + int ret; + + aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL); + if (!aw_bin) + return -ENOMEM; + + aw_bin->info.len = data_len; + memcpy(aw_bin->info.data, data, data_len); + + ret = aw_parsing_bin_file(aw_dev, aw_bin); + if (ret < 0) { + dev_err(aw_dev->dev, "parse bin failed"); + goto parse_bin_failed; + } + + if ((aw_bin->all_bin_parse_num != 1) || + (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) { + dev_err(aw_dev->dev, "bin num or type error"); + goto parse_bin_failed; + } + + if (aw_bin->header_info[0].valid_data_len % 4) { + dev_err(aw_dev->dev, "bin data len get error!"); + goto parse_bin_failed; + } + + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = + data + aw_bin->header_info[0].valid_data_addr; + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = + aw_bin->header_info[0].valid_data_len; + prof_desc->prof_st = AW88395_PROFILE_OK; + + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + + return 0; + +parse_bin_failed: + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + return ret; +} + static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr, struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc) { @@ -447,6 +495,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg return aw_dev_prof_parse_multi_bin( aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, cfg_dde->data_size, scene_prof_desc); + case ACF_SEC_TYPE_HDR_REG: + return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, + cfg_dde->data_size, scene_prof_desc); default: dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type); break; @@ -527,7 +578,49 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, return 0; } -static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, + struct aw_all_prof_info all_prof_info) +{ + struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + int num = 0; + int i; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) + prof_info->count++; + } + + dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count); + + if (!prof_info->count) { + dev_err(aw_dev->dev, "no profile data"); + return -EPERM; + } + + prof_info->prof_desc = devm_kcalloc(aw_dev->dev, + prof_info->count, sizeof(struct aw_prof_desc), + GFP_KERNEL); + if (!prof_info->prof_desc) + return -ENOMEM; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) { + if (num >= prof_info->count) { + dev_err(aw_dev->dev, "overflow count[%d]", + prof_info->count); + return -EINVAL; + } + prof_info->prof_desc[num] = prof_desc[i]; + prof_info->prof_desc[num].id = i; + num++; + } + } + + return 0; +} + +static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; @@ -606,9 +699,22 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, goto exit; } - ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); - if (ret < 0) - goto exit; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + case AW88261_CHIP_ID: + ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + default: + dev_err(aw_dev->dev, "valid prof unsupported"); + ret = -EINVAL; + break; + } aw_dev->prof_info.prof_name_list = profile_name; @@ -679,16 +785,37 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, @@ -699,15 +826,35 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev, @@ -756,6 +903,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev, prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; (*cur_scene_id)++; break; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + dev_err(aw_dev->dev, "parse reg bin with hdr failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; default: dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type); return -EINVAL; diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index e64f24e97150..e7a7c02efaf3 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -96,6 +96,7 @@ enum aw88395_id { AW88395_CHIP_ID = 0x2049, + AW88261_CHIP_ID = 0x2113, }; #define AW88395_REG_MAX (0x7D) -- cgit v1.2.3 From 028a2ae256916eeae1040049d2d0129535ace60e Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 4 Aug 2023 19:47:49 +0800 Subject: ASoC: codecs: Add aw88261 amplifier driver Add i2c and amplifier registration for aw88261 and their associated operation functions. Signed-off-by: Weidong Wang Link: https://lore.kernel.org/r/20230804114749.215460-4-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 15 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw88261.c | 1298 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/aw88261.h | 459 ++++++++++++++++ 4 files changed, 1774 insertions(+) create mode 100644 sound/soc/codecs/aw88261.c create mode 100644 sound/soc/codecs/aw88261.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8aba442d1978..ef279a27eb51 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -56,6 +56,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AUDIO_IIO_AUX imply SND_SOC_AW8738 imply SND_SOC_AW88395 + imply SND_SOC_AW88261 imply SND_SOC_BT_SCO imply SND_SOC_BD28623 imply SND_SOC_CHV3_CODEC @@ -653,6 +654,20 @@ config SND_SOC_AW88395 digital Smart K audio amplifier with an integrated 10V smart boost convert. +config SND_SOC_AW88261 + tristate "Soc Audio for awinic aw88261" + depends on I2C + select CRC8 + select REGMAP_I2C + select GPIOLIB + select SND_SOC_AW88395_LIB + help + This option enables support for aw88261 Smart PA. + The awinic AW88261 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier. The output voltage of + boost converter can be adjusted smartly according to + the input amplitude. + config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index be367839cfa4..2bdc0ef29a9e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -50,6 +50,7 @@ snd-soc-aw8738-objs := aw8738.o snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o snd-soc-aw88395-objs := aw88395/aw88395.o \ aw88395/aw88395_device.o +snd-soc-aw88261-objs := aw88261.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-chv3-codec-objs := chv3-codec.o @@ -434,6 +435,7 @@ obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o +obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c new file mode 100644 index 000000000000..82923b454dd4 --- /dev/null +++ b/sound/soc/codecs/aw88261.c @@ -0,0 +1,1298 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.c -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang +// Author: Weidong Wang +// + +#include +#include +#include +#include +#include +#include "aw88261.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h" + +static const struct regmap_config aw88261_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88261_REG_MAX - 1, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int real_value, volume; + unsigned int reg_value; + + volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL); + real_value = DB_TO_REG_VAL(volume); + + regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, ®_value); + + real_value = (real_value | (reg_value & AW88261_VOL_START_MASK)); + + dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value); + + regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value); +} + +static void aw88261_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw88261_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, + aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88261_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88261_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88261_MUTE_VOL) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + if (flag) + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE); +} + +static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + if (pwd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE); +} + +static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + if (amppd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE); +} + +static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw88261_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE); + aw88261_dev_fade_in(aw_dev); + } +} + +static void aw88261_dev_clear_int_status(struct aw_device *aw_dev) +{ + unsigned int int_status; + + /* read int status and clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + /* make sure int status is clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + + dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status); +} + +static int aw88261_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return ret; +} + +static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return ret; + } + } + + return -EPERM; +} + +static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88261_CCO_MUX_MASK); + if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88261_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88261_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return ret; +} + +static int aw88261_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + + check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) + & AW88261_BIT_SYSST_CHECK; + if (check_val != AW88261_BIT_SYSST_CHECK) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, AW88261_BIT_SYSST_CHECK); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + if (uls_hmute) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_DISABLE_VALUE); +} + +static void aw88261_reg_force_set(struct aw88261 *aw88261) +{ + if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) { + /* set FORCE_PWM */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG, + AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE); + /* set BOOST_OS_WIDTH */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG, + AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE); + /* set BURST_LOOPR */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG, + AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE); + /* set RSQN_DLY */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG, + AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE); + /* set BURST_SSMODE */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG, + AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE); + /* set BST_BURST */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG, + AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE); + } else { + dev_dbg(aw88261->aw_pa->dev, "needn't set reg value"); + } +} + +static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk) +{ + u16 reg_icalk, reg_icalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, ®_val); + if (ret) + return ret; + + reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, ®_val); + if (ret) + return ret; + + reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK); + + reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT); + + if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK)) + reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG; + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk) +{ + u16 reg_vcalk, reg_vcalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + + reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + + reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK); + + reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT); + + if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK) + reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG); + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw88261_dev_set_vcalb(struct aw_device *aw_dev) +{ + int16_t icalk_val, vcalk_val; + int icalk, vcalk, vcalb; + u32 reg_val; + int ret; + + ret = aw88261_dev_get_icalk(aw_dev, &icalk_val); + if (ret) + return ret; + + ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val); + if (ret) + return ret; + + icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val; + vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val; + if (!vcalk) + return -EINVAL; + + vcalb = AW88261_VCAL_FACTOR * icalk / vcalk; + reg_val = (unsigned int)vcalb; + + dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x", + icalk, vcalk, vcalb, reg_val); + ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val); + + return ret; +} + +static int aw88261_dev_reg_update(struct aw88261 *aw88261, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int read_val, efcheck_val, read_vol; + int data_len, i, ret; + int16_t *reg_data; + u16 reg_val; + u8 reg_addr; + + if (!len || !data) { + dev_err(aw_dev->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88261_SYSCTRL_REG) { + aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK); + ret = regmap_read(aw_dev->regmap, reg_addr, &read_val); + if (ret) + break; + + read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) | + (~AW88261_HMUTE_MASK); + reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK); + reg_val |= read_val; + + /* enable uls hmute */ + reg_val &= AW88261_ULS_HMUTE_MASK; + reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE; + } + + if (reg_addr == AW88261_DBGCTRL_REG) { + efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK); + if (efcheck_val == AW88261_OR_VALUE) + aw88261->efuse_check = AW88261_EF_OR_CHECK; + else + aw88261->efuse_check = AW88261_EF_AND_CHECK; + } + + /* i2stxen */ + if (reg_addr == AW88261_I2SCTRL3_REG) { + /* close tx */ + reg_val &= AW88261_I2STXEN_MASK; + reg_val |= AW88261_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88261_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88261_VOL_MASK)) >> + AW88261_VOL_START_BIT; + aw_dev->volume_desc.init_volume = + REG_VAL_TO_DB(read_vol); + } + + if (reg_addr == AW88261_VSNTM1_REG) + continue; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + break; + } + + ret = aw88261_dev_set_vcalb(aw_dev); + if (ret) + return ret; + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + + /* keep min volume */ + aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume); + + return ret; +} + +static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return NULL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return prof_info->prof_name_list[prof_desc->id]; +} + +static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88261_dev_fw_update(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index); + if (!prof_name) { + dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88261_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw88261_dev_reg_update(aw88261, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static int aw88261_dev_start(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (aw_dev->status == AW88261_DEV_PW_ON) { + dev_info(aw_dev->dev, "already power on"); + return 0; + } + + /* power on */ + aw88261_dev_pwd(aw_dev, false); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + + ret = aw88261_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw88261_dev_amppd(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 50); + + /* check i2s status */ + ret = aw88261_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + /* enable tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, true); + + if (aw88261->amppd_st) + aw88261_dev_amppd(aw_dev, true); + + aw88261_reg_force_set(aw88261); + + /* close uls mute */ + aw88261_dev_uls_hmute(aw_dev, false); + + /* close mute */ + if (!aw88261->mute_st) + aw88261_dev_mute(aw_dev, false); + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + aw_dev->status = AW88261_DEV_PW_ON; + + return 0; + +sysst_check_fail: + aw88261_dev_i2s_tx_enable(aw_dev, false); + aw88261_dev_clear_int_status(aw_dev); + aw88261_dev_amppd(aw_dev, true); +pll_check_fail: + aw88261_dev_pwd(aw_dev, true); + aw_dev->status = AW88261_DEV_PW_OFF; + + return ret; +} + +static int aw88261_dev_stop(struct aw_device *aw_dev) +{ + if (aw_dev->status == AW88261_DEV_PW_OFF) { + dev_info(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88261_DEV_PW_OFF; + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + /* set mute */ + aw88261_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + /* enable amppd */ + aw88261_dev_amppd(aw_dev, true); + + /* set power down */ + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_reg_update(struct aw88261 *aw88261, bool force) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (force) { + ret = regmap_write(aw_dev->regmap, + AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } else { + if (aw_dev->prof_cur != aw_dev->prof_index) { + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static void aw88261_start_pa(struct aw88261 *aw88261) +{ + int ret, i; + + for (i = 0; i < AW88261_START_RETRIES; i++) { + ret = aw88261_reg_update(aw88261, aw88261->phase_sync); + if (ret) { + dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i); + continue; + } + ret = aw88261_dev_start(aw88261); + if (ret) { + dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i); + continue; + } else { + dev_info(aw88261->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88261_startup_work(struct work_struct *work) +{ + struct aw88261 *aw88261 = + container_of(work, struct aw88261, start_work.work); + + mutex_lock(&aw88261->lock); + aw88261_start_pa(aw88261); + mutex_unlock(&aw88261->lock); +} + +static void aw88261_start(struct aw88261 *aw88261, bool sync_start) +{ + if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK) + return; + + if (aw88261->aw_pa->status == AW88261_DEV_PW_ON) + return; + + if (sync_start == AW88261_SYNC_START) + aw88261_start_pa(aw88261); + else + queue_delayed_work(system_wq, + &aw88261->start_work, + AW88261_START_WORK_DELAY_MS); +} + +static struct snd_soc_dai_driver aw88261_dai[] = { + { + .name = "aw88261-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + }, +}; + +static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + +static int aw88261_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + /* check the index whether is valid */ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + /* check the index whether change */ + if (aw_dev->prof_index == index) + return -EPERM; + + aw_dev->prof_index = index; + + return 0; +} + +static int aw88261_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + const char *prof_name; + char *name; + int count; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88261->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + + prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count); + if (!prof_name) { + strscpy(uinfo->value.enumerated.name, "null", + strlen("null") + 1); + return 0; + } + + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88261_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index; + + return 0; +} + +static int aw88261_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + int ret; + + /* pa stop or stopping just set profile */ + mutex_lock(&aw88261->lock); + ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88261->lock); + return 0; + } + + if (aw88261->aw_pa->status) { + aw88261_dev_stop(aw88261->aw_pa); + aw88261_start(aw88261, AW88261_SYNC_START); + } + + mutex_unlock(&aw88261->lock); + + return 1; +} + +static int aw88261_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88261_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (vol_desc->ctl_volume != value) { + vol_desc->ctl_volume = value; + aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume); + + return 1; + } + + return 0; +} + +static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step; + + return 0; +} + +static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88261->aw_pa->fade_step != value) { + aw88261->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new aw88261_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG, + 6, AW88261_MUTE_VOL, 0, aw88261_volume_get, + aw88261_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0, + aw88261_get_fade_step, aw88261_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_in_time, aw88261_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_out_time, aw88261_set_fade_out_time), + AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info, + aw88261_profile_get, aw88261_profile_set), +}; + +static int aw88261_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88261->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88261_start(aw88261, AW88261_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88261_dev_stop(aw88261->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88261->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0, + aw88261_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("DAC Output"), + + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("ADC Input"), +}; + +static const struct snd_soc_dapm_route aw88261_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88261_frcset_check(struct aw88261 *aw88261) +{ + unsigned int reg_val; + u16 temh, teml, tem; + int ret; + + ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + temh = ((u16)reg_val & (~AW88261_TEMH_MASK)); + + ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + teml = ((u16)reg_val & (~AW88261_TEML_MASK)); + + if (aw88261->efuse_check == AW88261_EF_OR_CHECK) + tem = (temh | teml); + else + tem = (temh & teml); + + if (tem == AW88261_DEFAULT_CFG) + aw88261->frcset_en = AW88261_FRCSET_ENABLE; + else + aw88261->frcset_en = AW88261_FRCSET_DISABLE; + + dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d", + tem, aw88261->frcset_en); + + return ret; +} + +static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + + ret = regmap_write(aw_dev->regmap, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + aw_dev->fade_in_time = AW88261_500_US; + aw_dev->fade_out_time = AW88261_500_US; + aw_dev->prof_cur = AW88261_INIT_PROFILE; + aw_dev->prof_index = AW88261_INIT_PROFILE; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + ret = aw88261_frcset_check(aw88261); + if (ret) { + dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret); + return ret; + } + + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + + aw88261_dev_mute(aw_dev, true); + + aw88261_dev_i2s_tx_enable(aw_dev, false); + + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + aw88261_dev_amppd(aw_dev, true); + + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_request_firmware_file(struct aw88261 *aw88261) +{ + const struct firmware *cont = NULL; + int ret; + + aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "load [%s] failed!", AW88261_ACF_FILE); + + dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n", + AW88261_ACF_FILE, cont ? cont->size : 0); + + aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88261->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88261->aw_cfg->len = (int)cont->size; + memcpy(aw88261->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg); + if (ret) { + dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE); + return ret; + } + + mutex_lock(&aw88261->lock); + /* aw device init */ + ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); + if (ret) + dev_err(aw88261->aw_pa->dev, "dev init failed"); + mutex_unlock(&aw88261->lock); + + return ret; +} + +static int aw88261_codec_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work); + + ret = aw88261_request_firmware_file(aw88261); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "aw88261_request_firmware_file failed\n"); + + /* add widgets */ + ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets, + ARRAY_SIZE(aw88261_dapm_widgets)); + if (ret) + return ret; + + /* add route */ + ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map, + ARRAY_SIZE(aw88261_audio_map)); + if (ret) + return ret; + + ret = snd_soc_add_component_controls(component, aw88261_controls, + ARRAY_SIZE(aw88261_controls)); + + return ret; +} + +static void aw88261_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88261->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88261 = { + .probe = aw88261_codec_probe, + .remove = aw88261_codec_remove, +}; + +static void aw88261_hw_reset(struct aw88261 *aw88261) +{ + gpiod_set_value_cansleep(aw88261->reset_gpio, 0); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); + gpiod_set_value_cansleep(aw88261->reset_gpio, 1); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); +} + +static void aw88261_parse_channel_dt(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW88261_DEV_DEFAULT_CH; + u32 sync_enable = false; + + of_property_read_u32(np, "sound-channel", &channel_value); + of_property_read_u32(np, "sync-flag", &sync_enable); + + aw_dev->channel = channel_value; + aw88261->phase_sync = sync_enable; +} + +static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + /* read chip id */ + ret = regmap_read(regmap, AW88261_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88261_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + + dev_info(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + (*aw88261)->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW88261_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = 0; + aw_dev->fw_status = AW88261_DEV_FW_FAILED; + aw_dev->fade_step = AW88261_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE; + aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL; + aw88261_parse_channel_dt(*aw88261); + + return ret; +} + +static int aw88261_i2c_probe(struct i2c_client *i2c) +{ + struct aw88261 *aw88261; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, ret, "check_functionality failed"); + + aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL); + if (!aw88261) + return -ENOMEM; + + mutex_init(&aw88261->lock); + + i2c_set_clientdata(i2c, aw88261); + + aw88261->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(aw88261->reset_gpio)) + dev_info(&i2c->dev, "reset gpio not defined\n"); + else + aw88261_hw_reset(aw88261); + + aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config); + if (IS_ERR(aw88261->regmap)) { + ret = PTR_ERR(aw88261->regmap); + return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret); + } + + /* aw pa init */ + ret = aw88261_init(&aw88261, i2c, aw88261->regmap); + if (ret) + return ret; + + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88261, + aw88261_dai, ARRAY_SIZE(aw88261_dai)); + if (ret) + dev_err(&i2c->dev, "failed to register aw88261: %d", ret); + + return ret; +} + +static const struct i2c_device_id aw88261_i2c_id[] = { + { AW88261_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id); + +static struct i2c_driver aw88261_i2c_driver = { + .driver = { + .name = AW88261_I2C_NAME, + }, + .probe = aw88261_i2c_probe, + .id_table = aw88261_i2c_id, +}; +module_i2c_driver(aw88261_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h new file mode 100644 index 000000000000..4f3dbf438510 --- /dev/null +++ b/sound/soc/codecs/aw88261.h @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.h -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang +// Author: Weidong Wang +// + +#ifndef __AW88261_H__ +#define __AW88261_H__ + +#define AW88261_ID_REG (0x00) +#define AW88261_SYSST_REG (0x01) +#define AW88261_SYSINT_REG (0x02) +#define AW88261_SYSINTM_REG (0x03) +#define AW88261_SYSCTRL_REG (0x04) +#define AW88261_SYSCTRL2_REG (0x05) +#define AW88261_I2SCTRL1_REG (0x06) +#define AW88261_I2SCTRL2_REG (0x07) +#define AW88261_I2SCTRL3_REG (0x08) +#define AW88261_DACCFG1_REG (0x09) +#define AW88261_DACCFG2_REG (0x0A) +#define AW88261_DACCFG3_REG (0x0B) +#define AW88261_DACCFG4_REG (0x0C) +#define AW88261_DACCFG5_REG (0x0D) +#define AW88261_DACCFG6_REG (0x0E) +#define AW88261_DACCFG7_REG (0x0F) +#define AW88261_DACCFG8_REG (0x10) +#define AW88261_PWMCTRL1_REG (0x11) +#define AW88261_PWMCTRL2_REG (0x12) +#define AW88261_I2SCFG1_REG (0x13) +#define AW88261_DBGCTRL_REG (0x14) +#define AW88261_DACCFG9_REG (0x15) +#define AW88261_DACCFG10_REG (0x16) +#define AW88261_DACST_REG (0x20) +#define AW88261_VBAT_REG (0x21) +#define AW88261_TEMP_REG (0x22) +#define AW88261_PVDD_REG (0x23) +#define AW88261_ISNDAT_REG (0x24) +#define AW88261_VSNDAT_REG (0x25) +#define AW88261_I2SINT_REG (0x26) +#define AW88261_I2SCAPCNT_REG (0x27) +#define AW88261_ANASTA1_REG (0x28) +#define AW88261_ANASTA2_REG (0x29) +#define AW88261_ANASTA3_REG (0x2A) +#define AW88261_TESTDET_REG (0x2B) +#define AW88261_DSMCFG1_REG (0x30) +#define AW88261_DSMCFG2_REG (0x31) +#define AW88261_DSMCFG3_REG (0x32) +#define AW88261_DSMCFG4_REG (0x33) +#define AW88261_DSMCFG5_REG (0x34) +#define AW88261_DSMCFG6_REG (0x35) +#define AW88261_DSMCFG7_REG (0x36) +#define AW88261_DSMCFG8_REG (0x37) +#define AW88261_TESTIN_REG (0x38) +#define AW88261_TESTOUT_REG (0x39) +#define AW88261_SADCCTRL1_REG (0x3A) +#define AW88261_SADCCTRL2_REG (0x3B) +#define AW88261_SADCCTRL3_REG (0x3C) +#define AW88261_SADCCTRL4_REG (0x3D) +#define AW88261_SADCCTRL5_REG (0x3E) +#define AW88261_SADCCTRL6_REG (0x3F) +#define AW88261_SADCCTRL7_REG (0x40) +#define AW88261_VSNTM1_REG (0x50) +#define AW88261_VSNTM2_REG (0x51) +#define AW88261_ISNCTRL1_REG (0x52) +#define AW88261_ISNCTRL2_REG (0x53) +#define AW88261_PLLCTRL1_REG (0x54) +#define AW88261_PLLCTRL2_REG (0x55) +#define AW88261_PLLCTRL3_REG (0x56) +#define AW88261_CDACTRL1_REG (0x57) +#define AW88261_CDACTRL2_REG (0x58) +#define AW88261_DITHERCFG1_REG (0x59) +#define AW88261_DITHERCFG2_REG (0x5A) +#define AW88261_DITHERCFG3_REG (0x5B) +#define AW88261_CPCTRL_REG (0x5C) +#define AW88261_BSTCTRL1_REG (0x60) +#define AW88261_BSTCTRL2_REG (0x61) +#define AW88261_BSTCTRL3_REG (0x62) +#define AW88261_BSTCTRL4_REG (0x63) +#define AW88261_BSTCTRL5_REG (0x64) +#define AW88261_BSTCTRL6_REG (0x65) +#define AW88261_BSTCTRL7_REG (0x66) +#define AW88261_BSTCTRL8_REG (0x67) +#define AW88261_BSTCTRL9_REG (0x68) +#define AW88261_TM_REG (0x6F) +#define AW88261_TESTCTRL1_REG (0x70) +#define AW88261_TESTCTRL2_REG (0x71) +#define AW88261_EFCTRL1_REG (0x72) +#define AW88261_EFCTRL2_REG (0x73) +#define AW88261_EFWH_REG (0x74) +#define AW88261_EFWM2_REG (0x75) +#define AW88261_EFWM1_REG (0x76) +#define AW88261_EFWL_REG (0x77) +#define AW88261_EFRH4_REG (0x78) +#define AW88261_EFRH3_REG (0x79) +#define AW88261_EFRH2_REG (0x7A) +#define AW88261_EFRH1_REG (0x7B) +#define AW88261_EFRL4_REG (0x7C) +#define AW88261_EFRL3_REG (0x7D) +#define AW88261_EFRL2_REG (0x7E) +#define AW88261_EFRL1_REG (0x7F) + +#define AW88261_REG_MAX (0x80) +#define AW88261_EF_DBMD_MASK (0xfff7) +#define AW88261_OR_VALUE (0x0008) + +#define AW88261_TEMH_MASK (0x83ff) +#define AW88261_TEML_MASK (0x83ff) +#define AW88261_DEFAULT_CFG (0x0000) + +#define AW88261_ICALK_SHIFT (0) +#define AW88261_ICALKL_SHIFT (0) +#define AW88261_VCALK_SHIFT (0) +#define AW88261_VCALKL_SHIFT (0) + +#define AW88261_AMPPD_START_BIT (1) +#define AW88261_AMPPD_BITS_LEN (1) +#define AW88261_AMPPD_MASK \ + (~(((1<> AW88261_VOL_6DB_START) * \ + AW88261_VOLUME_STEP_DB) + \ + ((value) & AW88261_REG_TO_DB)) +#define DB_TO_REG_VAL(value) ((((value) / AW88261_VOLUME_STEP_DB) << \ + AW88261_VOL_6DB_START) + \ + ((value) % AW88261_VOLUME_STEP_DB)) + +#define AW88261_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = profile_info, \ + .get = profile_get, \ + .put = profile_set, \ +} + +enum { + AW88261_SYNC_START = 0, + AW88261_ASYNC_START, +}; + +enum aw88261_id { + AW88261_CHIP_ID = 0x2113, +}; + +enum { + AW88261_500_US = 500, + AW88261_1000_US = 1000, + AW88261_2000_US = 2000, +}; + +enum { + AW88261_DEV_PW_OFF = 0, + AW88261_DEV_PW_ON, +}; + +enum { + AW88261_DEV_FW_FAILED = 0, + AW88261_DEV_FW_OK, +}; + +enum { + AW88261_EF_AND_CHECK = 0, + AW88261_EF_OR_CHECK, +}; + +enum { + AW88261_FRCSET_DISABLE = 0, + AW88261_FRCSET_ENABLE, +}; + +struct aw88261 { + struct aw_device *aw_pa; + struct mutex lock; + struct gpio_desc *reset_gpio; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + int efuse_check; + int frcset_en; + unsigned int mute_st; + unsigned int amppd_st; + + unsigned char phase_sync; +}; + +#endif -- cgit v1.2.3 From bee6cf1a80b54548a039e224c651bb15b644a480 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sun, 16 Jul 2023 20:22:20 +0200 Subject: x86/sev: Do not try to parse for the CC blob on non-AMD hardware Tao Liu reported a boot hang on an Intel Atom machine due to an unmapped EFI config table. The reason being that the CC blob which contains the CPUID page for AMD SNP guests is parsed for before even checking whether the machine runs on AMD hardware. Usually that's not a problem on !AMD hw - it simply won't find the CC blob's GUID and return. However, if any parts of the config table pointers array is not mapped, the kernel will #PF very early in the decompressor stage without any opportunity to recover. Therefore, do a superficial CPUID check before poking for the CC blob. This will fix the current issue on real hardware. It would also work as a guest on a non-lying hypervisor. For the lying hypervisor, the check is done again, *after* parsing the CC blob as the real CPUID page will be present then. Clear the #VC handler in case SEV-{ES,SNP} hasn't been detected, as a precaution. Fixes: c01fce9cef84 ("x86/compressed: Add SEV-SNP feature detection/setup") Reported-by: Tao Liu Signed-off-by: Borislav Petkov (AMD) Acked-by: Tom Lendacky Tested-by: Tao Liu Cc: Link: https://lore.kernel.org/r/20230601072043.24439-1-ltao@redhat.com --- arch/x86/boot/compressed/idt_64.c | 9 ++++++++- arch/x86/boot/compressed/sev.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c index 6debb816e83d..3cdf94b41456 100644 --- a/arch/x86/boot/compressed/idt_64.c +++ b/arch/x86/boot/compressed/idt_64.c @@ -63,7 +63,14 @@ void load_stage2_idt(void) set_idt_entry(X86_TRAP_PF, boot_page_fault); #ifdef CONFIG_AMD_MEM_ENCRYPT - set_idt_entry(X86_TRAP_VC, boot_stage2_vc); + /* + * Clear the second stage #VC handler in case guest types + * needing #VC have not been detected. + */ + if (sev_status & BIT(1)) + set_idt_entry(X86_TRAP_VC, boot_stage2_vc); + else + set_idt_entry(X86_TRAP_VC, NULL); #endif load_boot_idt(&boot_idt_desc); diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c index 09dc8c187b3c..c3e343bd4760 100644 --- a/arch/x86/boot/compressed/sev.c +++ b/arch/x86/boot/compressed/sev.c @@ -404,13 +404,46 @@ void sev_enable(struct boot_params *bp) if (bp) bp->cc_blob_address = 0; + /* + * Do an initial SEV capability check before snp_init() which + * loads the CPUID page and the same checks afterwards are done + * without the hypervisor and are trustworthy. + * + * If the HV fakes SEV support, the guest will crash'n'burn + * which is good enough. + */ + + /* Check for the SME/SEV support leaf */ + eax = 0x80000000; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + if (eax < 0x8000001f) + return; + + /* + * Check for the SME/SEV feature: + * CPUID Fn8000_001F[EAX] + * - Bit 0 - Secure Memory Encryption support + * - Bit 1 - Secure Encrypted Virtualization support + * CPUID Fn8000_001F[EBX] + * - Bits 5:0 - Pagetable bit position used to indicate encryption + */ + eax = 0x8000001f; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + /* Check whether SEV is supported */ + if (!(eax & BIT(1))) + return; + /* * Setup/preliminary detection of SNP. This will be sanity-checked * against CPUID/MSR values later. */ snp = snp_init(bp); - /* Check for the SME/SEV support leaf */ + /* Now repeat the checks with the SNP CPUID table. */ + + /* Recheck the SME/SEV support leaf */ eax = 0x80000000; ecx = 0; native_cpuid(&eax, &ebx, &ecx, &edx); @@ -418,7 +451,7 @@ void sev_enable(struct boot_params *bp) return; /* - * Check for the SME/SEV feature: + * Recheck for the SME/SEV feature: * CPUID Fn8000_001F[EAX] * - Bit 0 - Secure Memory Encryption support * - Bit 1 - Secure Encrypted Virtualization support -- cgit v1.2.3 From 2cbd80642b76480c9b0697297af917d9388a0b46 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Aug 2023 22:17:32 +0200 Subject: gfs2: Fix freeze consistency check in gfs2_trans_add_meta Function gfs2_trans_add_meta() checks for the SDF_FROZEN flag to make sure that no buffers are added to a transaction while the filesystem is frozen. With the recent freeze/thaw rework, the SDF_FROZEN flag is cleared after thaw_super() is called, which is sufficient for serializing freeze/thaw. However, other filesystem operations started after thaw_super() may now be calling gfs2_trans_add_meta() before the SDF_FROZEN flag is cleared, which will trigger the SDF_FROZEN check in gfs2_trans_add_meta(). Fix that by checking the s_writers.frozen state instead. In addition, make sure not to call gfs2_assert_withdraw() with the sd_log_lock spin lock held. Check for a withdrawn filesystem before checking for a frozen filesystem, and don't pin/add buffers to the current transaction in case of a failure in either case. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/trans.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index ec1631257978..7e835be7032d 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -230,9 +230,11 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) { struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; + struct super_block *sb = sdp->sd_vfs; struct gfs2_bufdata *bd; struct gfs2_meta_header *mh; struct gfs2_trans *tr = current->journal_info; + bool withdraw = false; lock_buffer(bh); if (buffer_pinned(bh)) { @@ -266,13 +268,15 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) (unsigned long long)bd->bd_bh->b_blocknr); BUG(); } - if (unlikely(test_bit(SDF_FROZEN, &sdp->sd_flags))) { - fs_info(sdp, "GFS2:adding buf while frozen\n"); - gfs2_assert_withdraw(sdp, 0); - } if (unlikely(gfs2_withdrawn(sdp))) { fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n", (unsigned long long)bd->bd_bh->b_blocknr); + goto out_unlock; + } + if (unlikely(sb->s_writers.frozen == SB_FREEZE_COMPLETE)) { + fs_info(sdp, "GFS2:adding buf while frozen\n"); + withdraw = true; + goto out_unlock; } gfs2_pin(sdp, bd->bd_bh); mh->__pad0 = cpu_to_be64(0); @@ -281,6 +285,8 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) tr->tr_num_buf_new++; out_unlock: gfs2_log_unlock(sdp); + if (withdraw) + gfs2_assert_withdraw(sdp, 0); out: unlock_buffer(bh); } -- cgit v1.2.3 From 0be8432166a61abc537e1247e530f4b85970b56b Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 2 Aug 2023 09:24:12 -0500 Subject: gfs2: Don't use filemap_splice_read Starting with patch 2cb1e08985, gfs2 started using the new function filemap_splice_read rather than the old (and subsequently deleted) function generic_file_splice_read. filemap_splice_read works by taking references to a number of folios in the page cache and splicing those folios into a pipe. The folios are then read from the pipe and the folio references are dropped. This can take an arbitrary amount of time. We cannot allow that in gfs2 because those folio references will pin the inode glock to the node and prevent it from being demoted, which can lead to cluster-wide deadlocks. Instead, use copy_splice_read. (In addition, the old generic_file_splice_read called into ->read_iter, which called gfs2_file_read_iter, which took the inode glock during the operation. The new filemap_splice_read interface does not take the inode glock anymore. This is fixable, but it still wouldn't prevent cluster-wide deadlocks.) Fixes: 2cb1e08985e3 ("splice: Use filemap_splice_read() instead of generic_file_splice_read()") Signed-off-by: Bob Peterson Signed-off-by: Andreas Gruenbacher --- fs/gfs2/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 1bf3c4453516..b43fa8b8fc05 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1578,7 +1578,7 @@ const struct file_operations gfs2_file_fops = { .fsync = gfs2_fsync, .lock = gfs2_lock, .flock = gfs2_flock, - .splice_read = filemap_splice_read, + .splice_read = copy_splice_read, .splice_write = gfs2_file_splice_write, .setlease = simple_nosetlease, .fallocate = gfs2_fallocate, @@ -1609,7 +1609,7 @@ const struct file_operations gfs2_file_fops_nolock = { .open = gfs2_open, .release = gfs2_release, .fsync = gfs2_fsync, - .splice_read = filemap_splice_read, + .splice_read = copy_splice_read, .splice_write = gfs2_file_splice_write, .setlease = generic_setlease, .fallocate = gfs2_fallocate, -- cgit v1.2.3 From 5e720f8c8c9d959283c3908bbf32a91a01a86547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 7 Aug 2023 08:37:45 +0200 Subject: cpufreq: amd-pstate: fix global sysfs attribute type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 3666062b87ec ("cpufreq: amd-pstate: move to use bus_get_dev_root()") the "amd_pstate" attributes where moved from a dedicated kobject to the cpu root kobject. While the dedicated kobject expects to contain kobj_attributes the root kobject needs device_attributes. As the changed arguments are not used by the callbacks it works most of the time. However CFI will detect this issue: [ 4947.849350] CFI failure at dev_attr_show+0x24/0x60 (target: show_status+0x0/0x70; expected type: 0x8651b1de) ... [ 4947.849409] Call Trace: [ 4947.849410] [ 4947.849411] ? __warn+0xcf/0x1c0 [ 4947.849414] ? dev_attr_show+0x24/0x60 [ 4947.849415] ? report_cfi_failure+0x4e/0x60 [ 4947.849417] ? handle_cfi_failure+0x14c/0x1d0 [ 4947.849419] ? __cfi_show_status+0x10/0x10 [ 4947.849420] ? handle_bug+0x4f/0x90 [ 4947.849421] ? exc_invalid_op+0x1a/0x60 [ 4947.849422] ? asm_exc_invalid_op+0x1a/0x20 [ 4947.849424] ? __cfi_show_status+0x10/0x10 [ 4947.849425] ? dev_attr_show+0x24/0x60 [ 4947.849426] sysfs_kf_seq_show+0xa6/0x110 [ 4947.849433] seq_read_iter+0x16c/0x4b0 [ 4947.849436] vfs_read+0x272/0x2d0 [ 4947.849438] ksys_read+0x72/0xe0 [ 4947.849439] do_syscall_64+0x76/0xb0 [ 4947.849440] ? do_user_addr_fault+0x252/0x650 [ 4947.849442] ? exc_page_fault+0x7a/0x1b0 [ 4947.849443] entry_SYSCALL_64_after_hwframe+0x72/0xdc Fixes: 3666062b87ec ("cpufreq: amd-pstate: move to use bus_get_dev_root()") Reported-by: Jannik GlĂŒckert Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217765 Link: https://lore.kernel.org/lkml/c7f1bf9b-b183-bf6e-1cbb-d43f72494083@gmail.com/ Cc: All applicable Signed-off-by: Thomas Weißschuh Reviewed-by: Greg Kroah-Hartman Reviewed-by: Nathan Chancellor Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/amd-pstate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 81fba0dcbee9..9a1e194d5cf8 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1012,8 +1012,8 @@ static int amd_pstate_update_status(const char *buf, size_t size) return 0; } -static ssize_t show_status(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret; @@ -1024,7 +1024,7 @@ static ssize_t show_status(struct kobject *kobj, return ret; } -static ssize_t store_status(struct kobject *a, struct kobj_attribute *b, +static ssize_t status_store(struct device *a, struct device_attribute *b, const char *buf, size_t count) { char *p = memchr(buf, '\n', count); @@ -1043,7 +1043,7 @@ cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); cpufreq_freq_attr_ro(amd_pstate_highest_perf); cpufreq_freq_attr_rw(energy_performance_preference); cpufreq_freq_attr_ro(energy_performance_available_preferences); -define_one_global_rw(status); +static DEVICE_ATTR_RW(status); static struct freq_attr *amd_pstate_attr[] = { &amd_pstate_max_freq, @@ -1062,7 +1062,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = { }; static struct attribute *pstate_global_attributes[] = { - &status.attr, + &dev_attr_status.attr, NULL }; -- cgit v1.2.3 From 0b15afc9038146bb2009e7924b1ead2e919b2a56 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Jul 2023 20:00:35 +0200 Subject: tpm/tpm_tis: Disable interrupts for TUXEDO InfinityBook S 15/17 Gen7 TUXEDO InfinityBook S 15/17 Gen7 suffers from an IRQ problem on tpm_tis like a few other laptops. Add an entry for the workaround. Cc: stable@vger.kernel.org Fixes: e644b2f498d2 ("tpm, tpm_tis: Enable interrupt test") Link: https://bugzilla.suse.com/show_bug.cgi?id=1213645 Signed-off-by: Takashi Iwai Acked-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index cc42cf3de960..a98773ac2e55 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -162,6 +162,14 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"), }, }, + { + .callback = tpm_tis_disable_irq, + .ident = "TUXEDO InfinityBook S 15/17 Gen7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_MATCH(DMI_PRODUCT_NAME, "TUXEDO InfinityBook S 15/17 Gen7"), + }, + }, { .callback = tpm_tis_disable_irq, .ident = "UPX-TGL", -- cgit v1.2.3 From 0de030b308236a1392f924f527cf74614d8b6aef Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 11 Jun 2023 07:32:10 -0400 Subject: sysctl: set variable key_sysctls storage-class-specifier to static smatch reports security/keys/sysctl.c:12:18: warning: symbol 'key_sysctls' was not declared. Should it be static? This variable is only used in its defining file, so it should be static. Signed-off-by: Tom Rix Signed-off-by: Jarkko Sakkinen --- security/keys/sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index b72b82bb20c6..b348e1679d5d 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c @@ -9,7 +9,7 @@ #include #include "internal.h" -struct ctl_table key_sysctls[] = { +static struct ctl_table key_sysctls[] = { { .procname = "maxkeys", .data = &key_quota_maxkeys, -- cgit v1.2.3 From 554b841d470338a3b1d6335b14ee1cd0c8f5d754 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 2 Aug 2023 07:25:33 -0500 Subject: tpm: Disable RNG for all AMD fTPMs The TPM RNG functionality is not necessary for entropy when the CPU already supports the RDRAND instruction. The TPM RNG functionality was previously disabled on a subset of AMD fTPM series, but reports continue to show problems on some systems causing stutter root caused to TPM RNG functionality. Expand disabling TPM RNG use for all AMD fTPMs whether they have versions that claim to have fixed or not. To accomplish this, move the detection into part of the TPM CRB registration and add a flag indicating that the TPM should opt-out of registration to hwrng. Cc: stable@vger.kernel.org # 6.1.y+ Fixes: b006c439d58d ("hwrng: core - start hwrng kthread also for untrusted sources") Fixes: f1324bbc4011 ("tpm: disable hwrng for fTPM on some AMD designs") Reported-by: daniil.stas@posteo.net Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217719 Reported-by: bitlord0xff@gmail.com Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217212 Signed-off-by: Mario Limonciello Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 68 ++------------------------------------------- drivers/char/tpm/tpm_crb.c | 30 ++++++++++++++++++++ include/linux/tpm.h | 1 + 3 files changed, 33 insertions(+), 66 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index cf5499e51999..e904aae9771b 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -510,70 +510,6 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) return 0; } -/* - * Some AMD fTPM versions may cause stutter - * https://www.amd.com/en/support/kb/faq/pa-410 - * - * Fixes are available in two series of fTPM firmware: - * 6.x.y.z series: 6.0.18.6 + - * 3.x.y.z series: 3.57.y.5 + - */ -#ifdef CONFIG_X86 -static bool tpm_amd_is_rng_defective(struct tpm_chip *chip) -{ - u32 val1, val2; - u64 version; - int ret; - - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) - return false; - - ret = tpm_request_locality(chip); - if (ret) - return false; - - ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val1, NULL); - if (ret) - goto release; - if (val1 != 0x414D4400U /* AMD */) { - ret = -ENODEV; - goto release; - } - ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, &val1, NULL); - if (ret) - goto release; - ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, &val2, NULL); - -release: - tpm_relinquish_locality(chip); - - if (ret) - return false; - - version = ((u64)val1 << 32) | val2; - if ((version >> 48) == 6) { - if (version >= 0x0006000000180006ULL) - return false; - } else if ((version >> 48) == 3) { - if (version >= 0x0003005700000005ULL) - return false; - } else { - return false; - } - - dev_warn(&chip->dev, - "AMD fTPM version 0x%llx causes system stutter; hwrng disabled\n", - version); - - return true; -} -#else -static inline bool tpm_amd_is_rng_defective(struct tpm_chip *chip) -{ - return false; -} -#endif /* CONFIG_X86 */ - static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); @@ -588,7 +524,7 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) static int tpm_add_hwrng(struct tpm_chip *chip) { if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) || - tpm_amd_is_rng_defective(chip)) + chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) return 0; snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), @@ -719,7 +655,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) && - !tpm_amd_is_rng_defective(chip)) + !(chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED)) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 1a5d09b18513..9eb1a1859012 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -463,6 +463,28 @@ static bool crb_req_canceled(struct tpm_chip *chip, u8 status) return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE; } +static int crb_check_flags(struct tpm_chip *chip) +{ + u32 val; + int ret; + + ret = crb_request_locality(chip, 0); + if (ret) + return ret; + + ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val, NULL); + if (ret) + goto release; + + if (val == 0x414D4400U /* AMD */) + chip->flags |= TPM_CHIP_FLAG_HWRNG_DISABLED; + +release: + crb_relinquish_locality(chip, 0); + + return ret; +} + static const struct tpm_class_ops tpm_crb = { .flags = TPM_OPS_AUTO_STARTUP, .status = crb_status, @@ -800,6 +822,14 @@ static int crb_acpi_add(struct acpi_device *device) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; + rc = tpm_chip_bootstrap(chip); + if (rc) + goto out; + + rc = crb_check_flags(chip); + if (rc) + goto out; + rc = tpm_chip_register(chip); out: diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 6a1e8f157255..4ee9d13749ad 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -283,6 +283,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6), TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7), TPM_CHIP_FLAG_SUSPENDED = BIT(8), + TPM_CHIP_FLAG_HWRNG_DISABLED = BIT(9), }; #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) -- cgit v1.2.3 From e117e7adc637e364b599dc766f1d740698e7e027 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 4 Aug 2023 17:08:40 +0000 Subject: tpm/tpm_tis: Disable interrupts for Lenovo P620 devices The Lenovo ThinkStation P620 suffers from an irq storm issue like various other Lenovo machines, so add an entry for it to tpm_tis_dmi_table and force polling. It is worth noting that 481c2d14627d (tpm,tpm_tis: Disable interrupts after 1000 unhandled IRQs) does not seem to fix the problem on this machine, but setting 'tpm_tis.interrupts=0' on the kernel command line does. [jarkko@kernel.org: truncated the commit ID in the description to 12 characters] Cc: stable@vger.kernel.org # v6.4+ Fixes: e644b2f498d2 ("tpm, tpm_tis: Enable interrupt test") Signed-off-by: Jonathan McDowell Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index a98773ac2e55..ac4daaf294a3 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -162,6 +162,14 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"), }, }, + { + .callback = tpm_tis_disable_irq, + .ident = "ThinkStation P620", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P620"), + }, + }, { .callback = tpm_tis_disable_irq, .ident = "TUXEDO InfinityBook S 15/17 Gen7", -- cgit v1.2.3 From 72dbde0f2afbe4af8e8595a89c650ae6b9d9c36f Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Mon, 7 Aug 2023 12:24:15 +1000 Subject: io_uring: correct check for O_TMPFILE O_TMPFILE is actually __O_TMPFILE|O_DIRECTORY. This means that the old check for whether RESOLVE_CACHED can be used would incorrectly think that O_DIRECTORY could not be used with RESOLVE_CACHED. Cc: stable@vger.kernel.org # v5.12+ Fixes: 3a81fd02045c ("io_uring: enable LOOKUP_CACHED path resolution for filename lookups") Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/r/20230807-resolve_cached-o_tmpfile-v3-1-e49323e1ef6f@cyphar.com Signed-off-by: Jens Axboe --- io_uring/openclose.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/io_uring/openclose.c b/io_uring/openclose.c index 10ca57f5bd24..e3fae26e025d 100644 --- a/io_uring/openclose.c +++ b/io_uring/openclose.c @@ -35,9 +35,11 @@ static bool io_openat_force_async(struct io_open *open) { /* * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open, - * it'll always -EAGAIN + * it'll always -EAGAIN. Note that we test for __O_TMPFILE because + * O_TMPFILE includes O_DIRECTORY, which isn't a flag we need to force + * async for. */ - return open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE); + return open->how.flags & (O_TRUNC | O_CREAT | __O_TMPFILE); } static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) -- cgit v1.2.3 From 72cc654970658e88a1cdea08f06b11c218efa4da Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 16 Jul 2023 14:28:10 +0300 Subject: net/mlx5e: Take RTNL lock when needed before calling xdp_set_features() Hold RTNL lock when calling xdp_set_features() with a registered netdev, as the call triggers the netdev notifiers. This could happen when switching from uplink rep to nic profile for example. This resolves the following call trace: RTNL: assertion failed at net/core/dev.c (1953) WARNING: CPU: 6 PID: 112670 at net/core/dev.c:1953 call_netdevice_notifiers_info+0x7c/0x80 Modules linked in: sch_mqprio sch_mqprio_lib act_tunnel_key act_mirred act_skbedit cls_matchall nfnetlink_cttimeout act_gact cls_flower sch_ingress bonding ib_umad ip_gre rdma_ucm mlx5_vfio_pci ipip tunnel4 ip6_gre gre mlx5_ib vfio_pci vfio_pci_core vfio_iommu_type1 ib_uverbs vfio mlx5_core ib_ipoib geneve nf_tables ip6_tunnel tunnel6 iptable_raw openvswitch nsh rpcrdma ib_iser libiscsi scsi_transport_iscsi rdma_cm iw_cm ib_cm ib_core xt_conntrack xt_MASQUERADE nf_conntrack_netlink nfnetlink xt_addrtype iptable_nat nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay zram zsmalloc fuse [last unloaded: ib_uverbs] CPU: 6 PID: 112670 Comm: devlink Not tainted 6.4.0-rc7_for_upstream_min_debug_2023_06_28_17_02 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 RIP: 0010:call_netdevice_notifiers_info+0x7c/0x80 Code: 90 ff 80 3d 2d 6b f7 00 00 75 c5 ba a1 07 00 00 48 c7 c6 e4 ce 0b 82 48 c7 c7 c8 f4 04 82 c6 05 11 6b f7 00 01 e8 a4 7c 8e ff <0f> 0b eb a2 0f 1f 44 00 00 55 48 89 e5 41 54 48 83 e4 f0 48 83 ec RSP: 0018:ffff8882a21c3948 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffffff82e6f880 RCX: 0000000000000027 RDX: ffff88885f99b5c8 RSI: 0000000000000001 RDI: ffff88885f99b5c0 RBP: 0000000000000028 R08: ffff88887ffabaa8 R09: 0000000000000003 R10: ffff88887fecbac0 R11: ffff88887ff7bac0 R12: ffff8882a21c3968 R13: ffff88811c018940 R14: 0000000000000000 R15: ffff8881274401a0 FS: 00007fe141c81800(0000) GS:ffff88885f980000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f787c28b948 CR3: 000000014bcf3005 CR4: 0000000000370ea0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ? __warn+0x79/0x120 ? call_netdevice_notifiers_info+0x7c/0x80 ? report_bug+0x17c/0x190 ? handle_bug+0x3c/0x60 ? exc_invalid_op+0x14/0x70 ? asm_exc_invalid_op+0x16/0x20 ? call_netdevice_notifiers_info+0x7c/0x80 ? call_netdevice_notifiers_info+0x7c/0x80 call_netdevice_notifiers+0x2e/0x50 mlx5e_set_xdp_feature+0x21/0x50 [mlx5_core] mlx5e_nic_init+0xf1/0x1a0 [mlx5_core] mlx5e_netdev_init_profile+0x76/0x110 [mlx5_core] mlx5e_netdev_attach_profile+0x1f/0x90 [mlx5_core] mlx5e_netdev_change_profile+0x92/0x160 [mlx5_core] mlx5e_netdev_attach_nic_profile+0x1b/0x30 [mlx5_core] mlx5e_vport_rep_unload+0xaa/0xc0 [mlx5_core] __esw_offloads_unload_rep+0x52/0x60 [mlx5_core] mlx5_esw_offloads_rep_unload+0x52/0x70 [mlx5_core] esw_offloads_unload_rep+0x34/0x70 [mlx5_core] esw_offloads_disable+0x2b/0x90 [mlx5_core] mlx5_eswitch_disable_locked+0x1b9/0x210 [mlx5_core] mlx5_devlink_eswitch_mode_set+0xf5/0x630 [mlx5_core] ? devlink_get_from_attrs_lock+0x9e/0x110 devlink_nl_cmd_eswitch_set_doit+0x60/0xe0 genl_family_rcv_msg_doit.isra.0+0xc2/0x110 genl_rcv_msg+0x17d/0x2b0 ? devlink_get_from_attrs_lock+0x110/0x110 ? devlink_nl_cmd_eswitch_get_doit+0x290/0x290 ? devlink_pernet_pre_exit+0xf0/0xf0 ? genl_family_rcv_msg_doit.isra.0+0x110/0x110 netlink_rcv_skb+0x54/0x100 genl_rcv+0x24/0x40 netlink_unicast+0x1f6/0x2c0 netlink_sendmsg+0x232/0x4a0 sock_sendmsg+0x38/0x60 ? _copy_from_user+0x2a/0x60 __sys_sendto+0x110/0x160 ? __count_memcg_events+0x48/0x90 ? handle_mm_fault+0x161/0x260 ? do_user_addr_fault+0x278/0x6e0 __x64_sys_sendto+0x20/0x30 do_syscall_64+0x3d/0x90 entry_SYSCALL_64_after_hwframe+0x46/0xb0 RIP: 0033:0x7fe141b1340a Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 RSP: 002b:00007fff61d03de8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 0000000000afab00 RCX: 00007fe141b1340a RDX: 0000000000000038 RSI: 0000000000afab00 RDI: 0000000000000003 RBP: 0000000000afa910 R08: 00007fe141d80200 R09: 000000000000000c R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000001 Fixes: 4d5ab0ad964d ("net/mlx5e: take into account device reconfiguration for xdp_features flag") Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 1c820119e438..c27df14df145 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -5266,6 +5266,7 @@ void mlx5e_destroy_q_counters(struct mlx5e_priv *priv) static int mlx5e_nic_init(struct mlx5_core_dev *mdev, struct net_device *netdev) { + const bool take_rtnl = netdev->reg_state == NETREG_REGISTERED; struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_flow_steering *fs; int err; @@ -5294,9 +5295,19 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev, mlx5_core_err(mdev, "TLS initialization failed, %d\n", err); mlx5e_health_create_reporters(priv); + + /* If netdev is already registered (e.g. move from uplink to nic profile), + * RTNL lock must be held before triggering netdev notifiers. + */ + if (take_rtnl) + rtnl_lock(); + /* update XDP supported features */ mlx5e_set_xdp_feature(netdev); + if (take_rtnl) + rtnl_unlock(); + return 0; } -- cgit v1.2.3 From ac5da544a3c2047cbfd715acd9cec8380d7fe5c6 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Fri, 14 Apr 2023 08:48:20 +0000 Subject: net/mlx5e: TC, Fix internal port memory leak The flow rule can be splited, and the extra post_act rules are added to post_act table. It's possible to trigger memleak when the rule forwards packets from internal port and over tunnel, in the case that, for example, CT 'new' state offload is allowed. As int_port object is assigned to the flow attribute of post_act rule, and its refcnt is incremented by mlx5e_tc_int_port_get(), but mlx5e_tc_int_port_put() is not called, the refcnt is never decremented, then int_port is never freed. The kmemleak reports the following error: unreferenced object 0xffff888128204b80 (size 64): comm "handler20", pid 50121, jiffies 4296973009 (age 642.932s) hex dump (first 32 bytes): 01 00 00 00 19 00 00 00 03 f0 00 00 04 00 00 00 ................ 98 77 67 41 81 88 ff ff 98 77 67 41 81 88 ff ff .wgA.....wgA.... backtrace: [<00000000e992680d>] kmalloc_trace+0x27/0x120 [<000000009e945a98>] mlx5e_tc_int_port_get+0x3f3/0xe20 [mlx5_core] [<0000000035a537f0>] mlx5e_tc_add_fdb_flow+0x473/0xcf0 [mlx5_core] [<0000000070c2cec6>] __mlx5e_add_fdb_flow+0x7cf/0xe90 [mlx5_core] [<000000005cc84048>] mlx5e_configure_flower+0xd40/0x4c40 [mlx5_core] [<000000004f8a2031>] mlx5e_rep_indr_offload.isra.0+0x10e/0x1c0 [mlx5_core] [<000000007df797dc>] mlx5e_rep_indr_setup_tc_cb+0x90/0x130 [mlx5_core] [<0000000016c15cc3>] tc_setup_cb_add+0x1cf/0x410 [<00000000a63305b4>] fl_hw_replace_filter+0x38f/0x670 [cls_flower] [<000000008bc9e77c>] fl_change+0x1fd5/0x4430 [cls_flower] [<00000000e7f766e4>] tc_new_tfilter+0x867/0x2010 [<00000000e101c0ef>] rtnetlink_rcv_msg+0x6fc/0x9f0 [<00000000e1111d44>] netlink_rcv_skb+0x12c/0x360 [<0000000082dd6c8b>] netlink_unicast+0x438/0x710 [<00000000fc568f70>] netlink_sendmsg+0x794/0xc50 [<0000000016e92590>] sock_sendmsg+0xc5/0x190 So fix this by moving int_port cleanup code to the flow attribute free helper, which is used by all the attribute free cases. Fixes: 8300f225268b ("net/mlx5e: Create new flow attr for multi table actions") Signed-off-by: Jianbo Liu Reviewed-by: Vlad Buslov Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 92377632f9e0..31708d5aa608 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1943,9 +1943,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_flow_attr *attr = flow->attr; - struct mlx5_esw_flow_attr *esw_attr; - esw_attr = attr->esw_attr; mlx5e_put_flow_tunnel_id(flow); remove_unready_flow(flow); @@ -1966,12 +1964,6 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, mlx5_tc_ct_match_del(get_ct_priv(priv), &flow->attr->ct_attr); - if (esw_attr->int_port) - mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->int_port); - - if (esw_attr->dest_int_port) - mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->dest_int_port); - if (flow_flag_test(flow, L3_TO_L2_DECAP)) mlx5e_detach_decap(priv, flow); @@ -4268,6 +4260,7 @@ static void mlx5_free_flow_attr_actions(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *attr) { struct mlx5_core_dev *counter_dev = get_flow_counter_dev(flow); + struct mlx5_esw_flow_attr *esw_attr; if (!attr) return; @@ -4285,6 +4278,18 @@ mlx5_free_flow_attr_actions(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *a mlx5e_tc_detach_mod_hdr(flow->priv, flow, attr); } + if (mlx5e_is_eswitch_flow(flow)) { + esw_attr = attr->esw_attr; + + if (esw_attr->int_port) + mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(flow->priv), + esw_attr->int_port); + + if (esw_attr->dest_int_port) + mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(flow->priv), + esw_attr->dest_int_port); + } + mlx5_tc_ct_delete_flow(get_ct_priv(flow->priv), attr); free_branch_attr(flow, attr->branch_true); -- cgit v1.2.3 From 8bfe1e19fb96d89fce14302e35cba0cd9f39d0a1 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Wed, 26 Jul 2023 14:38:03 +0300 Subject: net/mlx5: DR, Fix wrong allocation of modify hdr pattern Fixing wrong calculation of the modify hdr pattern size, where the previously calculated number would not be enough to accommodate the required number of actions. Fixes: da5d0027d666 ("net/mlx5: DR, Add cache for modify header pattern") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c index d6947fe13d56..8ca534ef5d03 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c @@ -82,7 +82,7 @@ dr_ptrn_alloc_pattern(struct mlx5dr_ptrn_mgr *mgr, u32 chunk_size; u32 index; - chunk_size = ilog2(num_of_actions); + chunk_size = ilog2(roundup_pow_of_two(num_of_actions)); /* HW modify action index granularity is at least 64B */ chunk_size = max_t(u32, chunk_size, DR_CHUNK_SIZE_8); -- cgit v1.2.3 From 06c868fde61fd0bbf9a7c7405f6eb9925bf0c2ed Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Mon, 26 Jun 2023 22:55:03 +0300 Subject: net/mlx5: Return correct EC_VF function ID The ECVF function ID range is 1..max_ec_vfs. Currently mlx5_vport_to_func_id returns 0..max_ec_vfs - 1. Which results in a syndrome when querying the caps with more recent firmware, or reading incorrect caps with older firmware that supports EC VFs. Fixes: 9ac0b128248e ("net/mlx5: Update vport caps query/set for EC VFs") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index c4be257c043d..682d3dc00dd1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -361,7 +361,7 @@ static inline bool mlx5_core_is_ec_vf_vport(const struct mlx5_core_dev *dev, u16 static inline int mlx5_vport_to_func_id(const struct mlx5_core_dev *dev, u16 vport, bool ec_vf_func) { - return ec_vf_func ? vport - mlx5_core_ec_vf_vport_base(dev) + return ec_vf_func ? vport - mlx5_core_ec_vf_vport_base(dev) + 1 : vport; } -- cgit v1.2.3 From 2dc2b3922d3c0f52d3a792d15dcacfbc4cc76b8f Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 11 Jul 2023 00:28:10 +0300 Subject: net/mlx5: Allow 0 for total host VFs When querying eswitch functions 0 is a valid number of host VFs. After introducing ARM SRIOV falling through to getting the max value from PCI results in using the total VFs allowed on the ARM for the host. Fixes: 86eec50beaf3 ("net/mlx5: Support querying max VFs from device"); Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 4e42a3b9b8ee..a2fc937d5461 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -285,8 +285,7 @@ static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev) host_total_vfs = MLX5_GET(query_esw_functions_out, out, host_params_context.host_total_vfs); kvfree(out); - if (host_total_vfs) - return host_total_vfs; + return host_total_vfs; } done: -- cgit v1.2.3 From 2d691c90f45ad2d0eafdd24c6abb0973a831c1d2 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 1 Aug 2023 21:46:00 +0300 Subject: net/mlx5: Fix devlink controller number for ECVF The controller number for ECVFs is always 0, because the ECPF must be the eswitch owner for EC VFs to be enabled. Fixes: dc13180824b7 ("net/mlx5: Enable devlink port for embedded cpu VF vports") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index af779c700278..fdf2be548e85 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -60,7 +60,7 @@ static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 } else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) { memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); dl_port->attrs.switch_id.id_len = ppid.id_len; - devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, + devlink_port_attrs_pci_vf_set(dl_port, 0, pfnum, vport_num - 1, false); } return dl_port; -- cgit v1.2.3 From 6b5926eb1c034affff3fb44a98cb8c67153847d8 Mon Sep 17 00:00:00 2001 From: Chris Mi Date: Wed, 26 Jul 2023 09:06:33 +0300 Subject: net/mlx5e: Unoffload post act rule when handling FIB events If having the following tc rule on stack device: filter parent ffff: protocol ip pref 3 flower chain 1 filter parent ffff: protocol ip pref 3 flower chain 1 handle 0x1 dst_mac 24:25:d0:e1:00:00 src_mac 02:25:d0:25:01:02 eth_type ipv4 ct_state +trk+new in_hw in_hw_count 1 action order 1: ct commit zone 0 pipe index 2 ref 1 bind 1 installed 3807 sec used 3779 sec firstused 3800 sec Action statistics: Sent 120 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 used_hw_stats delayed action order 2: tunnel_key set src_ip 192.168.1.25 dst_ip 192.168.1.26 key_id 4 dst_port 4789 csum pipe index 3 ref 1 bind 1 installed 3807 sec used 3779 sec firstused 3800 sec Action statistics: Sent 120 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 used_hw_stats delayed action order 3: mirred (Egress Redirect to device vxlan1) stolen index 9 ref 1 bind 1 installed 3807 sec used 3779 sec firstused 3800 sec Action statistics: Sent 120 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 used_hw_stats delayed When handling FIB events, the rule in post act will not be deleted. And because the post act rule has packet reformat and modify header actions, also will hit the following syndromes: mlx5_core 0000:08:00.0: mlx5_cmd_out_err:829:(pid 11613): DEALLOC_MODIFY_HEADER_CONTEXT(0x941) op_mod(0x0) failed, status bad resource state(0x9), syndrome (0x1ab444), err(-22) mlx5_core 0000:08:00.0: mlx5_cmd_out_err:829:(pid 11613): DEALLOC_PACKET_REFORMAT_CONTEXT(0x93e) op_mod(0x0) failed, status bad resource state(0x9), syndrome (0x179e84), err(-22) Fix it by unoffloading post act rule when handling FIB events. Fixes: 314e1105831b ("net/mlx5e: Add post act offload/unoffload API") Signed-off-by: Chris Mi Reviewed-by: Vlad Buslov Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c index 0c88cf47af01..1730f6a716ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c @@ -1461,10 +1461,12 @@ static void mlx5e_invalidate_encap(struct mlx5e_priv *priv, attr = mlx5e_tc_get_encap_attr(flow); esw_attr = attr->esw_attr; - if (flow_flag_test(flow, SLOW)) + if (flow_flag_test(flow, SLOW)) { mlx5e_tc_unoffload_from_slow_path(esw, flow); - else + } else { mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->attr); + mlx5e_tc_unoffload_flow_post_acts(flow); + } mlx5e_tc_detach_mod_hdr(priv, flow, attr); attr->modify_hdr = NULL; -- cgit v1.2.3 From 86ed7b773c01ba71617538b3b107c33fd9cf90b8 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Sun, 30 Jul 2023 09:26:27 +0300 Subject: net/mlx5: LAG, Check correct bucket when modifying LAG Cited patch introduced buckets in hash mode, but missed to update the ports/bucket check when modifying LAG. Fix the check. Fixes: 352899f384d4 ("net/mlx5: Lag, use buckets in hash mode") Signed-off-by: Shay Drory Reviewed-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c index d3a3fe4ce670..7d9bbb494d95 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/port_sel.c @@ -574,7 +574,7 @@ static int __mlx5_lag_modify_definers_destinations(struct mlx5_lag *ldev, for (i = 0; i < ldev->ports; i++) { for (j = 0; j < ldev->buckets; j++) { idx = i * ldev->buckets + j; - if (ldev->v2p_map[i] == ports[i]) + if (ldev->v2p_map[idx] == ports[idx]) continue; dest.vport.vhca_id = MLX5_CAP_GEN(ldev->pf[ports[idx] - 1].dev, -- cgit v1.2.3 From d006207625657322ba8251b6e7e829f9659755dc Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 19 Jul 2023 11:33:44 +0300 Subject: net/mlx5: Skip clock update work when device is in error state When device is in error state, marked by the flag MLX5_DEVICE_STATE_INTERNAL_ERROR, the HW and PCI may not be accessible and so clock update work should be skipped. Furthermore, such access through PCI in error state, after calling mlx5_pci_disable_device() can result in failing to recover from pci errors. Fixes: ef9814deafd0 ("net/mlx5e: Add HW timestamping (TS) support") Reported-and-tested-by: Ganesh G R Closes: https://lore.kernel.org/netdev/9bdb9b9d-140a-7a28-f0de-2e64e873c068@nvidia.com Signed-off-by: Moshe Shemesh Reviewed-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 973babfaff25..377372f0578a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -227,10 +227,15 @@ static void mlx5_timestamp_overflow(struct work_struct *work) clock = container_of(timer, struct mlx5_clock, timer); mdev = container_of(clock, struct mlx5_core_dev, clock); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) + goto out; + write_seqlock_irqsave(&clock->lock, flags); timecounter_read(&timer->tc); mlx5_update_clock_info_page(mdev); write_sequnlock_irqrestore(&clock->lock, flags); + +out: schedule_delayed_work(&timer->overflow_work, timer->overflow_period); } -- cgit v1.2.3 From aab8e1a200b926147db51e3f82fd07bb9edf6a98 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Sun, 23 Jul 2023 11:03:01 +0300 Subject: net/mlx5: Reload auxiliary devices in pci error handlers Handling pci errors should fully teardown and load back auxiliary devices, same as done through mlx5 health recovery flow. Fixes: 72ed5d5624af ("net/mlx5: Suspend auxiliary devices only in case of PCI device suspend") Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f42abc2ea73c..72ae560a1c68 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1989,7 +1989,7 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, mlx5_enter_error_state(dev, false); mlx5_error_sw_reset(dev); - mlx5_unload_one(dev, true); + mlx5_unload_one(dev, false); mlx5_drain_health_wq(dev); mlx5_pci_disable_device(dev); -- cgit v1.2.3 From 548ee049b19fb9a3d0a4335314d0d1217a521bc5 Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Sun, 11 Jun 2023 16:29:13 +0300 Subject: net/mlx5e: Add capability check for vnic counters Add missing capability check for each of the vnic counters exposed by devlink health reporter, and thus avoid unexpected behavior due to invalid access to registers. While at it, read only the exact number of bits for each counter whether it was 32 bits or 64 bits. Fixes: b0bc615df488 ("net/mlx5: Add vnic devlink health reporter to PFs/VFs") Fixes: a33682e4e78e ("net/mlx5e: Expose catastrophic steering error counters") Signed-off-by: Lama Kayal Reviewed-by: Gal Pressman Reviewed-by: Rahul Rameshbabu Reviewed-by: Maher Sanalla Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/diag/reporter_vnic.c | 116 ++++++++++++--------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c index b0128336ff01..e869c65d8e90 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c @@ -2,6 +2,7 @@ /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. */ #include "reporter_vnic.h" +#include "en_stats.h" #include "devlink.h" #define VNIC_ENV_GET64(vnic_env_stats, c) \ @@ -36,55 +37,72 @@ int mlx5_reporter_vnic_diagnose_counters(struct mlx5_core_dev *dev, if (err) return err; - err = devlink_fmsg_u64_pair_put(fmsg, "total_error_queues", - VNIC_ENV_GET64(&vnic, total_error_queues)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "send_queue_priority_update_flow", - VNIC_ENV_GET64(&vnic, send_queue_priority_update_flow)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "comp_eq_overrun", - VNIC_ENV_GET64(&vnic, comp_eq_overrun)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "async_eq_overrun", - VNIC_ENV_GET64(&vnic, async_eq_overrun)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "cq_overrun", - VNIC_ENV_GET64(&vnic, cq_overrun)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "invalid_command", - VNIC_ENV_GET64(&vnic, invalid_command)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "quota_exceeded_command", - VNIC_ENV_GET64(&vnic, quota_exceeded_command)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "nic_receive_steering_discard", - VNIC_ENV_GET64(&vnic, nic_receive_steering_discard)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "generated_pkt_steering_fail", - VNIC_ENV_GET64(&vnic, generated_pkt_steering_fail)); - if (err) - return err; - - err = devlink_fmsg_u64_pair_put(fmsg, "handled_pkt_steering_fail", - VNIC_ENV_GET64(&vnic, handled_pkt_steering_fail)); - if (err) - return err; + if (MLX5_CAP_GEN(dev, vnic_env_queue_counters)) { + err = devlink_fmsg_u32_pair_put(fmsg, "total_error_queues", + VNIC_ENV_GET(&vnic, total_error_queues)); + if (err) + return err; + + err = devlink_fmsg_u32_pair_put(fmsg, "send_queue_priority_update_flow", + VNIC_ENV_GET(&vnic, + send_queue_priority_update_flow)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, eq_overrun_count)) { + err = devlink_fmsg_u32_pair_put(fmsg, "comp_eq_overrun", + VNIC_ENV_GET(&vnic, comp_eq_overrun)); + if (err) + return err; + + err = devlink_fmsg_u32_pair_put(fmsg, "async_eq_overrun", + VNIC_ENV_GET(&vnic, async_eq_overrun)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, vnic_env_cq_overrun)) { + err = devlink_fmsg_u32_pair_put(fmsg, "cq_overrun", + VNIC_ENV_GET(&vnic, cq_overrun)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, invalid_command_count)) { + err = devlink_fmsg_u32_pair_put(fmsg, "invalid_command", + VNIC_ENV_GET(&vnic, invalid_command)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, quota_exceeded_count)) { + err = devlink_fmsg_u32_pair_put(fmsg, "quota_exceeded_command", + VNIC_ENV_GET(&vnic, quota_exceeded_command)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, nic_receive_steering_discard)) { + err = devlink_fmsg_u64_pair_put(fmsg, "nic_receive_steering_discard", + VNIC_ENV_GET64(&vnic, + nic_receive_steering_discard)); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, vnic_env_cnt_steering_fail)) { + err = devlink_fmsg_u64_pair_put(fmsg, "generated_pkt_steering_fail", + VNIC_ENV_GET64(&vnic, + generated_pkt_steering_fail)); + if (err) + return err; + + err = devlink_fmsg_u64_pair_put(fmsg, "handled_pkt_steering_fail", + VNIC_ENV_GET64(&vnic, handled_pkt_steering_fail)); + if (err) + return err; + } err = devlink_fmsg_obj_nest_end(fmsg); if (err) -- cgit v1.2.3 From f957172bf7c562df10dc57586118b1cbe15e6b00 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 5 Aug 2023 19:14:35 +0200 Subject: ASoC: lower "no backend DAIs enabled for ... Port" log severity If SNDRV_PCM_IOCTL_PREPARE is called when the mixer settings linking frontend and backend have not been setup yet this results in e.g. the following errors getting logged: [ 43.244549] Baytrail Audio Port: ASoC: no backend DAIs enabled for Baytrail Audio Port [ 43.244744] Baytrail Audio Port: ASoC: error at dpcm_fe_dai_prepare on Baytrail Audio Port: -22 pipewire triggers this leading to 96 lines getting logged after the user has logged into a GNOME session. Change the actual "no backend DAIs enabled for ... Port" error to dev_err_once() to avoid it getting repeated 48 times. While at it also improve the error by hinting the user how to fix this. To not make developing new UCM profiles harder, also log the error at dev_dbg() level all the time (vs once). So that e.g. dyndbg can be used to (re)enable the messages. Also changes _soc_pcm_ret() to not log for -EINVAL errors, to fix the other error getting logged 48 times. Userspace passing wrong parameters should not lead to dmesg messages. Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3407 Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230805171435.31696-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8896227e4fb7..3aa6b988cb4b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -38,6 +38,7 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, switch (ret) { case -EPROBE_DEFER: case -ENOTSUPP: + case -EINVAL: break; default: dev_err(rtd->dev, @@ -2466,8 +2467,11 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* there is no point preparing this FE if there are no BEs */ if (list_empty(&fe->dpcm[stream].be_clients)) { - dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n", - fe->dai_link->name); + /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles */ + dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n", + fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", + fe->dai_link->name); ret = -EINVAL; goto out; } -- cgit v1.2.3 From 93fd2be6eb80fe37570fbd87652ec07a4f7c5b5a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 25 Jul 2023 20:02:47 +0800 Subject: ASoC: SOF: ipc3-dtrace: Switch to memdup_user_nul() helper Use memdup_user_nul() helper instead of open-coding to simplify the code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230725120247.509422-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-dtrace.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index 35da85a45a9a..bd07f0472efd 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -196,15 +196,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user return -EINVAL; } - string = kmalloc(count + 1, GFP_KERNEL); - if (!string) - return -ENOMEM; - - if (copy_from_user(string, from, count)) { - ret = -EFAULT; - goto error; - } - string[count] = '\0'; + string = memdup_user_nul(from, count); + if (IS_ERR(string)) + return PTR_ERR(string); ret = trace_filter_parse(sdev, string, &num_elems, &elems); if (ret < 0) -- cgit v1.2.3 From 01f4fd27087078c90a0e22860d1dfa2cd0510791 Mon Sep 17 00:00:00 2001 From: Ziyang Xuan Date: Wed, 2 Aug 2023 19:43:20 +0800 Subject: bonding: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves BUG_ON(!vlan_info) is triggered in unregister_vlan_dev() with following testcase: # ip netns add ns1 # ip netns exec ns1 ip link add bond0 type bond mode 0 # ip netns exec ns1 ip link add bond_slave_1 type veth peer veth2 # ip netns exec ns1 ip link set bond_slave_1 master bond0 # ip netns exec ns1 ip link add link bond_slave_1 name vlan10 type vlan id 10 protocol 802.1ad # ip netns exec ns1 ip link add link bond0 name bond0_vlan10 type vlan id 10 protocol 802.1ad # ip netns exec ns1 ip link set bond_slave_1 nomaster # ip netns del ns1 The logical analysis of the problem is as follows: 1. create ETH_P_8021AD protocol vlan10 for bond_slave_1: register_vlan_dev() vlan_vid_add() vlan_info_alloc() __vlan_vid_add() // add [ETH_P_8021AD, 10] vid to bond_slave_1 2. create ETH_P_8021AD protocol bond0_vlan10 for bond0: register_vlan_dev() vlan_vid_add() __vlan_vid_add() vlan_add_rx_filter_info() if (!vlan_hw_filter_capable(dev, proto)) // condition established because bond0 without NETIF_F_HW_VLAN_STAG_FILTER return 0; if (netif_device_present(dev)) return dev->netdev_ops->ndo_vlan_rx_add_vid(dev, proto, vid); // will be never called // The slaves of bond0 will not refer to the [ETH_P_8021AD, 10] vid. 3. detach bond_slave_1 from bond0: __bond_release_one() vlan_vids_del_by_dev() list_for_each_entry(vid_info, &vlan_info->vid_list, list) vlan_vid_del(dev, vid_info->proto, vid_info->vid); // bond_slave_1 [ETH_P_8021AD, 10] vid will be deleted. // bond_slave_1->vlan_info will be assigned NULL. 4. delete vlan10 during delete ns1: default_device_exit_batch() dev->rtnl_link_ops->dellink() // unregister_vlan_dev() for vlan10 vlan_info = rtnl_dereference(real_dev->vlan_info); // real_dev of vlan10 is bond_slave_1 BUG_ON(!vlan_info); // bond_slave_1->vlan_info is NULL now, bug is triggered!!! Add S-VLAN tag related features support to bond driver. So the bond driver will always propagate the VLAN info to its slaves. Fixes: 8ad227ff89a7 ("net: vlan: add 802.1ad support") Suggested-by: Ido Schimmel Signed-off-by: Ziyang Xuan Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/20230802114320.4156068-1-william.xuanziyang@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 484c9e3e5e82..447b06ea4fc9 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5901,7 +5901,9 @@ void bond_setup(struct net_device *bond_dev) bond_dev->hw_features = BOND_VLAN_FEATURES | NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_FILTER; + NETIF_F_HW_VLAN_CTAG_FILTER | + NETIF_F_HW_VLAN_STAG_RX | + NETIF_F_HW_VLAN_STAG_FILTER; bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL; bond_dev->features |= bond_dev->hw_features; -- cgit v1.2.3 From 46622219aae2b67813fe31a7b8cb7da5baff5c8a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 7 Aug 2023 15:21:27 +0200 Subject: wireguard: allowedips: expand maximum node depth In the allowedips self-test, nodes are inserted into the tree, but it generated an even amount of nodes, but for checking maximum node depth, there is of course the root node, which makes the total number necessarily odd. With two few nodes added, it never triggered the maximum depth check like it should have. So, add 129 nodes instead of 128 nodes, and do so with a more straightforward scheme, starting with all the bits set, and shifting over one each time. Then increase the maximum depth to 129, and choose a better name for that variable to make it clear that it represents depth as opposed to bits. Cc: stable@vger.kernel.org Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") Signed-off-by: Jason A. Donenfeld Link: https://lore.kernel.org/r/20230807132146.2191597-2-Jason@zx2c4.com Signed-off-by: Jakub Kicinski --- drivers/net/wireguard/allowedips.c | 8 ++++---- drivers/net/wireguard/selftest/allowedips.c | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c index 5bf7822c53f1..0ba714ca5185 100644 --- a/drivers/net/wireguard/allowedips.c +++ b/drivers/net/wireguard/allowedips.c @@ -6,7 +6,7 @@ #include "allowedips.h" #include "peer.h" -enum { MAX_ALLOWEDIPS_BITS = 128 }; +enum { MAX_ALLOWEDIPS_DEPTH = 129 }; static struct kmem_cache *node_cache; @@ -42,7 +42,7 @@ static void push_rcu(struct allowedips_node **stack, struct allowedips_node __rcu *p, unsigned int *len) { if (rcu_access_pointer(p)) { - if (WARN_ON(IS_ENABLED(DEBUG) && *len >= MAX_ALLOWEDIPS_BITS)) + if (WARN_ON(IS_ENABLED(DEBUG) && *len >= MAX_ALLOWEDIPS_DEPTH)) return; stack[(*len)++] = rcu_dereference_raw(p); } @@ -55,7 +55,7 @@ static void node_free_rcu(struct rcu_head *rcu) static void root_free_rcu(struct rcu_head *rcu) { - struct allowedips_node *node, *stack[MAX_ALLOWEDIPS_BITS] = { + struct allowedips_node *node, *stack[MAX_ALLOWEDIPS_DEPTH] = { container_of(rcu, struct allowedips_node, rcu) }; unsigned int len = 1; @@ -68,7 +68,7 @@ static void root_free_rcu(struct rcu_head *rcu) static void root_remove_peer_lists(struct allowedips_node *root) { - struct allowedips_node *node, *stack[MAX_ALLOWEDIPS_BITS] = { root }; + struct allowedips_node *node, *stack[MAX_ALLOWEDIPS_DEPTH] = { root }; unsigned int len = 1; while (len > 0 && (node = stack[--len])) { diff --git a/drivers/net/wireguard/selftest/allowedips.c b/drivers/net/wireguard/selftest/allowedips.c index 78ebe2892a78..3d1f64ff2e12 100644 --- a/drivers/net/wireguard/selftest/allowedips.c +++ b/drivers/net/wireguard/selftest/allowedips.c @@ -593,16 +593,20 @@ bool __init wg_allowedips_selftest(void) wg_allowedips_remove_by_peer(&t, a, &mutex); test_negative(4, a, 192, 168, 0, 1); - /* These will hit the WARN_ON(len >= MAX_ALLOWEDIPS_BITS) in free_node + /* These will hit the WARN_ON(len >= MAX_ALLOWEDIPS_DEPTH) in free_node * if something goes wrong. */ - for (i = 0; i < MAX_ALLOWEDIPS_BITS; ++i) { - part = cpu_to_be64(~(1LLU << (i % 64))); - memset(&ip, 0xff, 16); - memcpy((u8 *)&ip + (i < 64) * 8, &part, 8); + for (i = 0; i < 64; ++i) { + part = cpu_to_be64(~0LLU << i); + memset(&ip, 0xff, 8); + memcpy((u8 *)&ip + 8, &part, 8); + wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex); + memcpy(&ip, &part, 8); + memset((u8 *)&ip + 8, 0, 8); wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex); } - + memset(&ip, 0, 16); + wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex); wg_allowedips_free(&t, &mutex); wg_allowedips_init(&t); -- cgit v1.2.3 From 7075b0c91b3cd5d32b4ac7403f771a3253d3fbf6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:40 -0500 Subject: ASoC: SOF: Intel: hda-mlink: fix off-by-one error The HCHAN parameter should be the highest channel number, not the channel count. While we're at it, handle LCHAN with the dual __ffs helper. Fixes: ccc2f0c1b6b6 ("ASoC: SOF: Intel: hda-mlink: add helper to program SoundWire PCMSyCM registers") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index b7cbf66badf5..acad3ea2f471 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -781,6 +781,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, { struct hdac_ext2_link *h2link; u16 __iomem *pcmsycm; + int hchan; + int lchan; u16 val; h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); @@ -791,9 +793,17 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, h2link->instance_offset * sublink + AZX_REG_SDW_SHIM_PCMSyCM(y); + if (channel_mask) { + hchan = __fls(channel_mask); + lchan = __ffs(channel_mask); + } else { + hchan = 0; + lchan = 0; + } + mutex_lock(&h2link->eml_lock); - hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask), + hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan, stream_id, dir); mutex_unlock(&h2link->eml_lock); -- cgit v1.2.3 From 7a52d7062e02af4a479da24b40cfd76b54c0cd6c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:41 -0500 Subject: ASoC: SOF: Intel: fix u16/32 confusion in LSDIID Likely a combination of copy-paste and test coverage problem. Oops. Fixes: 87a6ddc0cf1c ("ASoC: SOF: Intel: hda-mlink: program SoundWire LSDIID registers") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index acad3ea2f471..df87b3791c23 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -331,14 +331,14 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) return !!(val & cmdsync_mask); } -static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num) +static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) { - u32 val; + u16 val; - val = readl(lsdiid); + val = readw(lsdiid); val |= BIT(dev_num); - writel(val, lsdiid); + writew(val, lsdiid); } static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan, -- cgit v1.2.3 From defc0c638d20eec17ebb3dbf82709aba1ac2f0d4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Aug 2023 16:09:42 -0500 Subject: ASoC: SOF: ipc4: avoid uninitialized default instance 0 When a pipeline contains multiple DAI widgets, the pipe_widget is not set up except for the first DAI. This result in the pipe_widget having a default instance 0, which can conflict with another real the pipeline instance 0 and leads to spurious transitions. This patch makes sure the instance_id is properly initialized to a -EINVAL value. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 6 ++++++ sound/soc/sof/ipc4-topology.c | 1 + sound/soc/sof/topology.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index f3513796c189..e9ae38916434 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -234,6 +234,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { @@ -297,6 +300,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a4e1a70b607d..9bc94be072aa 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2319,6 +2319,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline->mem_usage = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); + swidget->instance_id = -EINVAL; } else { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 698129dccc7d..1afcbb134d2c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2157,6 +2157,8 @@ static int sof_complete(struct snd_soc_component *scomp) struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct snd_sof_widget *swidget; + pipe_widget->instance_id = -EINVAL; + /* Update the scheduler widget's IPC structure */ if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) { ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget); -- cgit v1.2.3 From ef8a29bae82fc635952de97fdd3bcf8e29d8c6be Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:43 -0500 Subject: ASoC: SOF: ipc4-topology: restore gateway config length The initial code had a logic flaw where the gateway config length kept increasing after each playback/capture trigger, with the DMA config TLV being added at every call of sof_ipc4_prepare_copier_module() This didn't cause any issues with regular playback/capture, but this was flagged as an error by firmware in the case of multiple amplifiers on different links. Fixes: a0659f81c348 ("ASoC: SOF: ipc4-topology: add DMA config TLV to IPC data") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 9bc94be072aa..0196cbfc0998 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1746,6 +1746,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); + /* + * Restore gateway config length now that IPC payload is prepared. This avoids + * counting the DMA CONFIG TLV multiple times + */ + copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4; + return 0; } -- cgit v1.2.3 From 701c0ba46fabc4715606f840119271a818209357 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:44 -0500 Subject: ASoC: SOF: Intel: hda: add interface definitions for ACE2.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All interfaces are accessible without the DSP and rely on the HDaudio DMA only. Signed-off-by: Pierre-Louis Bossart Reviewed-by: PĂ©ter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 64bebe1a72bb..6074b0ca13aa 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev) BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); interface_mask[1] = BIT(SOF_DAI_INTEL_HDA); break; + case SOF_INTEL_ACE_2_0: + interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | + BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); + interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */ + break; default: break; } -- cgit v1.2.3 From 64a63d9914a5e9278fcd81c6dbc095fc84b772d2 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Aug 2023 16:09:45 -0500 Subject: ASoC: SOF: Intel: LNL: Add support for Lunarlake platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add initial support for Lunarlake. For now only HDAudio interfaces are supported, DMIC/SSP/SoundWire require additional work so that the DAIs reuse the HDaudio DMA stream allocation. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: PĂ©ter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++ sound/soc/sof/intel/Makefile | 4 ++- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/lnl.c | 66 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/pci-lnl.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/intel/lnl.c create mode 100644 sound/soc/sof/intel/pci-lnl.c diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 69c1a370d3b6..9d0107932117 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_LNL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_LUNARLAKE + tristate "SOF support for Lunarlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_LNL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Lunarlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index fdb463c12e91..030574dbc998 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-dai-ops.o hda-bus.o \ skl.o hda-loader-skl.o \ - apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o + apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o snd-sof-intel-hda-mlink-objs := hda-mlink.o @@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-tgl-objs := pci-tgl.o snd-sof-pci-intel-mtl-objs := pci-mtl.o +snd-sof-pci-intel-lnl-objs := pci-lnl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o @@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3f7c6fb05e5d..fae3be291861 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -856,6 +856,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc mtl_chip_info; +extern const struct sof_intel_dsp_desc lnl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c new file mode 100644 index 000000000000..535a0fd36f38 --- /dev/null +++ b/sound/soc/sof/intel/lnl.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. + +/* + * Hardware interface for audio DSP on LunarLake. + */ + +#include +#include +#include +#include +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" +#include "hda.h" +#include + +/* Check if an SDW IRQ occurred */ +static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW); +} + +static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable); +} + +static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) +{ + lnl_enable_sdw_irq(sdev, false); + mtl_disable_ipc_interrupts(sdev); + return mtl_enable_interrupts(sdev, false); +} + +const struct sof_intel_dsp_desc lnl_chip_info = { + .cores_num = 5, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .enable_sdw_irq = lnl_enable_sdw_irq, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_2_0, +}; +EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c new file mode 100644 index 000000000000..55c757737a95 --- /dev/null +++ b/sound/soc/sof/intel/pci-lnl.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc lnl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_lnl_machines, + .alt_machines = snd_soc_acpi_intel_lnl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &lnl_chip_info, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .dspless_mode_supported = true, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "sof-lnl.ri", + }, + .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", + /* the MTL ops are still used for now */ + .ops = &sof_mtl_ops, + .ops_init = sof_mtl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_lnl_driver = { + .name = "sof-audio-pci-intel-lnl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_lnl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); -- cgit v1.2.3 From c22d53279709c46f2e19caf2886e38cee93d07ea Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:46 -0500 Subject: ASoC: SOF: Intel: split MTL and LNL operations It was just a matter of time before we found a case where we needed separate ops for MTL and LNL. For LNL we need to set the DMIC/SSP OFLEN bit in the probe and resume steps, and this can only be done cleanly with separate ops. The function prototypes in mtl.h were added in the same order as their implementation in mtl.c. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/intel/lnl.c | 67 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/mtl.c | 22 +++++++------- sound/soc/sof/intel/mtl.h | 22 ++++++++++++-- sound/soc/sof/intel/pci-lnl.c | 5 ++-- 5 files changed, 102 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index fae3be291861..17164fc42501 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -845,6 +845,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_mtl_ops; int sof_mtl_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_lnl_ops; +int sof_lnl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc apl_chip_info; diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 535a0fd36f38..65a78d9511e9 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -19,6 +19,73 @@ #include "hda.h" #include +/* LunarLake ops */ +struct snd_sof_dsp_ops sof_lnl_ops; +EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +int sof_lnl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* shutdown */ + sof_lnl_ops.shutdown = hda_dsp_shutdown; + + /* doorbell */ + sof_lnl_ops.irq_thread = mtl_ipc_irq_thread; + + /* ipc */ + sof_lnl_ops.send_msg = mtl_ipc_send_msg; + sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + + /* debug */ + sof_lnl_ops.debug_map = lnl_dsp_debugfs; + sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs); + sof_lnl_ops.dbg_dump = mtl_dsp_dump; + sof_lnl_ops.ipc_dump = mtl_ipc_dump; + + /* pre/post fw run */ + sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run; + sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run; + + /* parse platform specific extended manifest */ + sof_lnl_ops.parse_platform_ext_manifest = NULL; + + /* dsp core get/put */ + /* TODO: add core_get and core_put */ + + sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, &sof_lnl_ops); + + sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4; + + return 0; +}; +EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); + /* Check if an SDW IRQ occurred */ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 30fe77fd87bf..be3155f98944 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return false; } -static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; @@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) } /* pre fw run operations */ -static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; u32 dsphfpwrsts; @@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } -static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { int ret; @@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } -static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; u32 romdbgsts; @@ -495,7 +495,7 @@ err: return ret; } -static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; @@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } -static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } -static void mtl_ipc_dump(struct snd_sof_dev *sdev) +void mtl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; @@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } -static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream) +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct hdac_stream *hstream = substream->runtime->private_data; u32 llp_l, llp_u; diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 2794fe6e8139..02181490f12a 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -82,10 +82,28 @@ #define MTL_DSP_REG_HfIMRIS1 0x162088 #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) +bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); + void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev); void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev); -bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable); -int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev); +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + int mtl_power_down_dsp(struct snd_sof_dev *sdev); +int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +irqreturn_t mtl_ipc_irq_thread(int irq, void *context); + +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + +void mtl_ipc_dump(struct snd_sof_dev *sdev); + +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index 55c757737a95..1b12c280edb4 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -42,9 +42,8 @@ static const struct sof_dev_desc lnl_desc = { [SOF_INTEL_IPC4] = "sof-lnl.ri", }, .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", - /* the MTL ops are still used for now */ - .ops = &sof_mtl_ops, - .ops_init = sof_mtl_ops_init, + .ops = &sof_lnl_ops, + .ops_init = sof_lnl_ops_init, }; /* PCI IDs */ -- cgit v1.2.3 From e78576c4aa0d5b7185e1f5188578d9bfb2d43d4b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:47 -0500 Subject: ASoC: SOF: Intel: LNL: enable DMIC/SSP offload in probe/resume In the LunarLake hardware, the default IP ownership changed to the host driver, instead of the firmware in previous generation. In the absence of any capability negotiation, we need to assume a fixed partitioning between host driver and firmware. The OFLEN bit needs to be set as early as possible for resources handled by the firmware, since we can't control when the firmware might try to access the resources. For now DMIC and SSP are handled by the DSP firmware. SoundWire is a separate case, the OFLEN bit can be set when starting-up and resuming the aux device for each link. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 65a78d9511e9..3d919b0b6891 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -29,6 +29,55 @@ static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; +/* this helps allows the DSP to setup DMIC/SSP */ +static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus) +{ + int ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true); + if (ret < 0) + return ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true); + if (ret < 0) + return ret; + + return 0; +} + +static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_probe(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_runtime_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + int sof_lnl_ops_init(struct snd_sof_dev *sdev) { struct sof_ipc4_fw_data *ipc4_data; @@ -36,6 +85,9 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + /* probe */ + sof_lnl_ops.probe = lnl_hda_dsp_probe; + /* shutdown */ sof_lnl_ops.shutdown = hda_dsp_shutdown; @@ -63,6 +115,10 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) /* dsp core get/put */ /* TODO: add core_get and core_put */ + /* PM */ + sof_lnl_ops.resume = lnl_hda_dsp_resume; + sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume; + sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); -- cgit v1.2.3 From 12547730e5b7c41e2203003cda74f39f43739c53 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:48 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: add/select DMA ops for SSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DMA widget ops are almost similar to the HDaudio ones, with the exception of codec_dai_set_hext_stream() which is not relevant and the format calculation which isn't dependent on the codec dai. The DMA ops can be selected only starting with ACE_2_0. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: PĂ©ter Ujfalusi Link: https://lore.kernel.org/r/20230807210959.506849-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index e9ae38916434..05ef77be6435 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include "../ipc4-priv.h" @@ -219,6 +220,31 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev, return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); } +static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + + format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), + params_format(params), + params_physical_width(params), + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), params_channels(params), params_format(params)); + + return format_val; +} + +static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_ssp_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -363,6 +389,19 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hlink = hda_get_hlink, }; +static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = ssp_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -465,8 +504,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg case SOF_INTEL_IPC4: { struct sof_ipc4_copier *ipc4_copier = sdai->private; + const struct sof_intel_dsp_desc *chip; - if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { + chip = get_chip_info(sdev->pdata); + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_HDA: + { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; @@ -475,6 +519,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg return &hda_ipc4_dma_ops; } + case SOF_DAI_INTEL_SSP: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &ssp_ipc4_dma_ops; + default: + break; + } break; } default: -- cgit v1.2.3 From a8338e76457c14c56bb13fbb16c8607e80498499 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:49 -0500 Subject: ASoC: SOF: Intel: hda-dai: add ops for SSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new ops for SSP. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: PĂ©ter Ujfalusi Link: https://lore.kernel.org/r/20230807210959.506849-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 115 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 3297dea493aa..711854f59cf5 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include #include @@ -330,6 +332,96 @@ static const struct snd_soc_dai_ops hda_dai_ops = { #endif +static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *sdai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private; + + return ipc4_copier; +} + +static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct sof_ipc4_dma_config_tlv *dma_config_tlv; + const struct hda_dai_widget_dma_ops *ops; + struct sof_ipc4_dma_config *dma_config; + struct sof_ipc4_copier *ipc4_copier; + struct hdac_ext_stream *hext_stream; + struct hdac_stream *hstream; + struct snd_sof_dev *sdev; + int stream_id; + int ret; + + ops = hda_dai_get_ops(substream, cpu_dai); + if (!ops) { + dev_err(cpu_dai->dev, "DAI widget ops not set\n"); + return -EINVAL; + } + + /* use HDaudio stream handling */ + ret = hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret); + return ret; + } + + /* get stream_id */ + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) { + dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__); + return -ENODEV; + } + + hstream = &hext_stream->hstream; + stream_id = hstream->stream_tag; + + if (!stream_id) { + dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__); + return -ENODEV; + } + + /* configure TLV */ + ipc4_copier = widget_to_copier(w); + + dma_config_tlv = &ipc4_copier->dma_config_tlv; + dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; + /* dma_config_priv_size is zero */ + dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); + + dma_config = &dma_config_tlv->dma_config; + + dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA; + dma_config->pre_allocated_by_host = 1; + dma_config->dma_channel_id = stream_id - 1; + dma_config->stream_id = stream_id; + dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ + dma_config->dma_priv_config_size = 0; + + return 0; +} + +static int non_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int stream = substream->stream; + + return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); +} + +static const struct snd_soc_dai_ops ssp_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -384,7 +476,26 @@ static int hda_dai_suspend(struct hdac_bus *bus) return 0; } -#endif +static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "SSP")) + ops->drv[i].ops = &ssp_dai_ops; + } + } +} + +#else + +static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} + +#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { @@ -399,6 +510,8 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) #endif } + ssp_set_dai_drv_ops(sdev, ops); + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; -- cgit v1.2.3 From b6c508b46d84d88e617d8b9f38ffbe60470589d0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:50 -0500 Subject: ASoC: SOF: Intel: hda-dai: add DMIC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can reuse the same helpers as for SSP, with just the link type being different. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: PĂ©ter Ujfalusi Reviewed-by: Jaska Uimonen Link: https://lore.kernel.org/r/20230807210959.506849-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 55 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-dai.c | 24 +++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 05ef77be6435..b66886244f24 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -237,6 +237,36 @@ static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, return format_val; } +static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + snd_pcm_format_t format; + unsigned int channels; + unsigned int width; + + channels = params_channels(params); + format = params_format(params); + width = params_physical_width(params); + + if (format == SNDRV_PCM_FORMAT_S16_LE) { + format = SNDRV_PCM_FORMAT_S32_LE; + channels /= 2; + width = 32; + } + + format_val = snd_hdac_calc_stream_format(params_rate(params), channels, + format, + width, + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), channels, format); + + return format_val; +} + static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -245,6 +275,14 @@ static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, return hdac_bus_eml_ssp_get_hlink(bus); } +static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_dmic_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -402,6 +440,19 @@ static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { .get_hlink = ssp_get_hlink, }; +static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = dmic_calc_stream_format, + .get_hlink = dmic_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -523,6 +574,10 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) return NULL; return &ssp_ipc4_dma_ops; + case SOF_DAI_INTEL_DMIC: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &dmic_ipc4_dma_ops; default: break; } diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 711854f59cf5..08de9b614a83 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -422,6 +422,13 @@ static const struct snd_soc_dai_ops ssp_dai_ops = { .prepare = non_hda_dai_prepare, }; +static const struct snd_soc_dai_ops dmic_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -491,9 +498,25 @@ static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops } } +static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "DMIC")) + ops->drv[i].ops = &dmic_dai_ops; + } + } +} + #else static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} +static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ @@ -511,6 +534,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) } ssp_set_dai_drv_ops(sdev, ops); + dmic_set_dai_drv_ops(sdev, ops); if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; -- cgit v1.2.3 From f8ba62ac863c33fc0d8ac3f1270985c2b77f4377 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:51 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: only allocate/release streams for first CPU DAI When we have multiple CPU DAIs in a dailink, typically for SoundWire aggregated solutions with amplifiers on multiple links, we only want to allocate one HDaudio stream_tag. The simplest solution is to allocate the hext_stream/stream_tag for the DAI with index 0 in the dailink, and reuse the same stream for all other CPU DAIs. This assumption relies on serialization of DAIs by the ASoC core, where all CPU DAIs are handled in a loop. The stream release follows the same idea of releasing the tag for the first DAI only. Ideally we would want the loop to be handled in reverse-order to summetry, but there is no risk of reusing a stream_tag which is no longer valid. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index b66886244f24..9a6d995a8453 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -145,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; struct hdac_ext_stream *hext_stream; - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + /* only allocate a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + else + hext_stream = snd_soc_dai_get_dma_data(dai, substream); + if (!hext_stream) return NULL; @@ -160,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + /* only release a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, -- cgit v1.2.3 From bb0b992c1bb94e44ba40f82ddb2c4e6d5c9fcc9e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:52 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: add ops for SoundWire Same abstraction as SSP/DMIC, with only the get_hlink helper changing. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 9a6d995a8453..4ae211141c40 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -296,6 +296,14 @@ static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, return hdac_bus_eml_dmic_get_hlink(bus); } +static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_sdw_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -466,6 +474,19 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { .get_hlink = dmic_get_hlink, }; +static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = sdw_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -591,6 +612,11 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) return NULL; return &dmic_ipc4_dma_ops; + case SOF_DAI_INTEL_ALH: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &sdw_ipc4_dma_ops; + default: break; } -- cgit v1.2.3 From 2960ee5c4814ee50b7b9f030dd99382623a4d7f0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:53 -0500 Subject: ASoC: SOF: Intel: hda-dai: add helpers for SoundWire callbacks During the hw_params and hw_free stages, we need to map the stream tag and channels in the PCMSyCM registers. The trigger callback is just a wrapper. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 72 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 12 ++++++++ 2 files changed, 84 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 08de9b614a83..c984fa79b1ef 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -429,6 +429,78 @@ static const struct snd_soc_dai_ops dmic_dai_ops = { .prepare = non_hda_dai_prepare, }; +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + const struct hda_dai_widget_dma_ops *ops; + struct hdac_ext_stream *hext_stream; + struct snd_sof_dev *sdev; + int ret; + + ret = non_hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret); + return ret; + } + + ops = hda_dai_get_ops(substream, cpu_dai); + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) + return -ENODEV; + + /* in the case of SoundWire we need to program the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + GENMASK(params_channels(params) - 1, 0), + hdac_stream(hext_stream)->stream_tag, + substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_dev *sdev; + int ret; + + ret = hda_dai_hw_free(substream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); + return ret; + } + + sdev = widget_to_sdev(w); + + /* in the case of SoundWire we need to reset the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + 0, 0, substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + return hda_dai_trigger(substream, cmd, cpu_dai); +} + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 17164fc42501..4f60b722e5d5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -824,6 +824,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) #endif +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai); + /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); -- cgit v1.2.3 From 186ca4b522fec020f0201d4fcef09ea58b4d5701 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:54 -0500 Subject: ASoC: SOF: Intel: hda: add hw_params/free/trigger callbacks These callbacks are just wrappers to keep the code relatively clean. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6074b0ca13aa..67b2e00baf4e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -112,6 +112,34 @@ struct sdw_intel_ops sdw_callback = { .params_stream = sdw_params_stream, }; +static int sdw_ace2x_params_stream(struct device *dev, + struct sdw_intel_stream_params_data *params_data) +{ + return sdw_hda_dai_hw_params(params_data->substream, + params_data->hw_params, + params_data->dai, + params_data->link_id); +} + +static int sdw_ace2x_free_stream(struct device *dev, + struct sdw_intel_stream_free_data *free_data) +{ + return sdw_hda_dai_hw_free(free_data->substream, + free_data->dai, + free_data->link_id); +} + +static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +{ + return sdw_hda_dai_trigger(substream, cmd, dai); +} + +static struct sdw_intel_ops sdw_ace2x_callback = { + .params_stream = sdw_ace2x_params_stream, + .free_stream = sdw_ace2x_free_stream, + .trigger = sdw_ace2x_trigger, +}; + void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) { struct sof_intel_hda_dev *hdev; @@ -179,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.shim_base = hdev->desc->sdw_shim_base; res.alh_base = hdev->desc->sdw_alh_base; res.ext = false; + res.ops = &sdw_callback; } else { /* * retrieve eml_lock needed to protect shared registers @@ -196,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) */ res.hw_ops = &sdw_intel_lnl_hw_ops; res.ext = true; + res.ops = &sdw_ace2x_callback; + } res.irq = sdev->ipc_irq; res.handle = hdev->info.handle; res.parent = sdev->dev; - res.ops = &sdw_callback; + res.dev = sdev->dev; res.clock_stop_quirks = sdw_clock_stop_quirks; res.hbus = sof_to_bus(sdev); -- cgit v1.2.3 From 9362ab78f175db2003674e008ef1b8917725d502 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:55 -0500 Subject: ASoC: SOF: Intel: add abstraction for SoundWire wake-ups The existing code cannot work for LunarLake, let's add a layer of abstraction. No functional change in this patch. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda.c | 20 +++++++++++++++----- sound/soc/sof/intel/hda.h | 6 ++++++ sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/mtl.c | 1 + sound/soc/sof/intel/shim.h | 1 + sound/soc/sof/intel/tgl.c | 4 ++++ 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a95222e53ecf..c6fbf4285262 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 67b2e00baf4e..5c1e6ad2b7f2 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -399,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return sdw_intel_thread(irq, context); } -static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) { - u32 interface_mask = hda_get_interface_mask(sdev); struct sof_intel_hda_dev *hdev; - if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) - return false; - hdev = sdev->pdata->hw_pdata; if (hdev->sdw && snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -416,6 +412,20 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) return false; } +static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + u32 interface_mask = hda_get_interface_mask(sdev); + const struct sof_intel_dsp_desc *chip; + + if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) + return false; + + if (chip && chip->check_sdw_wakeen_irq) + return chip->check_sdw_wakeen_irq(sdev); + + return false; +} + void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 4f60b722e5d5..f19510e8ce87 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev); int hda_sdw_startup(struct snd_sof_dev *sdev); void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev); void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); @@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } +static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) +{ + return false; +} + static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { } diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 0f249efc6a5a..7ac10167a90d 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index be3155f98944..b84ca58da9d5 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = mtl_enable_sdw_irq, .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 207df48e27cf..9515d753c816 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -189,6 +189,7 @@ struct sof_intel_dsp_desc { int (*read_sdw_lcount)(struct snd_sof_dev *sdev); void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable); bool (*check_sdw_irq)(struct snd_sof_dev *sdev); + bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); int (*power_down_dsp)(struct snd_sof_dev *sdev); int (*disable_interrupts)(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 8e2b07e1612b..bb9f20253c99 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, -- cgit v1.2.3 From 34e38f03d7e77141ef6879c69ca55fc2a44b9f2e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:56 -0500 Subject: ASoC: SOF: Intel: hda-mlink: add helper to get sublink LSDIID register We need to retrieve the current value to deal with the HDAudio WAKEEN/WAKESTS setup. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/hda-mlink.h | 4 ++++ sound/soc/sof/intel/hda-mlink.c | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index 4f44f0bd5388..228114aca415 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -42,6 +42,7 @@ int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, i int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink); int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink); +int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid); int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num); int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, @@ -145,6 +146,9 @@ hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink) { return 0 static inline int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return 0; } +static inline int +hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) { return 0; } + static inline int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { return 0; } diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index df87b3791c23..9fbbcc1744db 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -331,6 +331,11 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) return !!(val & cmdsync_mask); } +static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid) +{ + return readw(lsdiid); +} + static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) { u16 val; @@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK); +int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) +{ + struct hdac_ext2_link *h2link; + struct hdac_ext_link *hlink; + + h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); + if (!h2link) + return -ENODEV; + + hlink = &h2link->hext_link; + + *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink)); + + return 0; +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK); + int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { struct hdac_ext2_link *h2link; -- cgit v1.2.3 From 699e146d9ebf42ee2a5d4e4e28f7a49c4aef0105 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:57 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: reset device count for SoundWire DAIs The solution used before LunarLake relies on a 'Multi-gateway' firmware configuration. This is no longer needed with the DMA hardware handling multiple links directly. To avoid adding a platform-specific quirk in the generic IPC4 code, this patch resets the device count when fetching the stream context. Suggested-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 4ae211141c40..ae4a5aa73bfc 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -434,6 +434,28 @@ out: return ret; } +static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = dai->private; + struct sof_ipc4_alh_configuration_blob *blob; + + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; + + /* + * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using + * the multi-gateway firmware configuration. The DMA hardware can take care of + * multiple links without needing any firmware assistance + */ + blob->alh_cfg.device_count = 1; + + return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream); +} + static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -475,7 +497,7 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { }; static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { - .get_hext_stream = hda_ipc4_get_hext_stream, + .get_hext_stream = sdw_hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, .setup_hext_stream = hda_setup_hext_stream, -- cgit v1.2.3 From 1eaff2647eb1dfbaa500fb5f28e032db5ad35b70 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:58 -0500 Subject: ASoC: SOF: IPC4: clarify 'pipeline_ids' usage and logs A pipeline is identified by two indices: 'instance_id' and 'pipeline_id' This is clearly seen in kernel logs when creating a pipeline "Create widget pipeline.20 instance 0 - pipe 20 - core 0" but other logs are less clear "ipc4 set pipeline 1 state 4" Change definitions and logs to make sure the logs clearly identify which of the two indices are used in state transitions. No functional change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 21 +++++++++++---------- sound/soc/sof/ipc4-topology.h | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0c905bd0fab4..802cbf73594e 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state /* trigger a single pipeline */ if (trigger_list->count == 1) - return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state); + return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], + state); primary = state; primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); @@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size); } -int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state) +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state) { struct sof_ipc4_msg msg = {{ 0 }}; u32 primary; - dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state); + dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); primary = state; - primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id); + primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id); primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); @@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, * for the first time */ if (spipe->started_count == spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_RESET: /* RESET if the pipeline is neither running nor paused */ if (!spipe->started_count && !spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_PAUSED: /* Pause the pipeline only when its started_count is 1 more than paused_count */ if (spipe->paused_count == (spipe->started_count - 1)) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; default: @@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, /* set state for pipeline if it was just triggered */ for (i = 0; i < trigger_list->count; i++) { - if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) { + if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { pipeline->state = state; break; } @@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); /* allocate memory for the pipeline data */ - trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), - GFP_KERNEL); + trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids, + pipeline_list->count), GFP_KERNEL); if (!trigger_list) return -ENOMEM; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 6dcf14886e85..d75f17f4749c 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -144,11 +144,11 @@ struct sof_ipc4_pipeline { /** * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data * @count: Number of pipelines to be triggered - * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered + * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered */ struct ipc4_pipeline_set_state_data { u32 count; - DECLARE_FLEX_ARRAY(u32, pipeline_ids); + DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids); } __packed; /** -- cgit v1.2.3 From 02c7f8729a5a1e78412177482372c3124edd4d62 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:59 -0500 Subject: ASoC: SOF: Intel: hda-mlink: add sublink to dev_dbg() log When using more than one sublink for amplifier aggregation, we need to add the sublink info to debug the programming sequences. No functional change, only additional precisions in the log. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 9fbbcc1744db..b592e687a87a 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -831,8 +831,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, val = readw(pcmsycm); - dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n", - channel_mask, stream_id, dir, val); + dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n", + sublink, channel_mask, stream_id, dir, val); return 0; } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK); -- cgit v1.2.3 From 04b5b5cb0136ce970333a9c6cec7e46adba1ea3a Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Thu, 3 Aug 2023 10:02:30 +0800 Subject: scsi: core: Fix possible memory leak if device_add() fails If device_add() returns error, the name allocated by dev_set_name() needs be freed. As the comment of device_add() says, put_device() should be used to decrease the reference count in the error path. So fix this by calling put_device(), then the name can be freed in kobject_cleanp(). Fixes: ee959b00c335 ("SCSI: convert struct class_device to struct device") Signed-off-by: Zhu Wang Link: https://lore.kernel.org/r/20230803020230.226903-1-wangzhu9@huawei.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/raid_class.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 898a0bdf8df6..711252e52d8e 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -248,6 +248,7 @@ int raid_component_add(struct raid_template *r,struct device *raid_dev, return 0; err_out: + put_device(&rc->dev); list_del(&rc->node); rd->component_count--; put_device(component_dev); -- cgit v1.2.3 From 41320b18a0e0dfb236dba4edb9be12dba1878156 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 1 Aug 2023 19:14:21 +0800 Subject: scsi: snic: Fix possible memory leak if device_add() fails If device_add() returns error, the name allocated by dev_set_name() needs be freed. As the comment of device_add() says, put_device() should be used to give up the reference in the error path. So fix this by calling put_device(), then the name can be freed in kobject_cleanp(). Fixes: c8806b6c9e82 ("snic: driver for Cisco SCSI HBA") Signed-off-by: Zhu Wang Acked-by: Narsimhulu Musini Link: https://lore.kernel.org/r/20230801111421.63651-1-wangzhu9@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_disc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index 3e2e5783924d..e429ad23c396 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -303,6 +303,7 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) "Snic Tgt: device_add, with err = %d\n", ret); + put_device(&tgt->dev); put_device(&snic->shost->shost_gendev); spin_lock_irqsave(snic->shost->host_lock, flags); list_del(&tgt->list); -- cgit v1.2.3 From b6d128f89a85771433a004e8656090ccbe1fb969 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 3 Aug 2023 17:18:12 +0900 Subject: scsi: ufs: renesas: Fix private allocation Should use devm_kzalloc() for struct ufs_renesas_priv because the .initialized should be false as default. Fixes: d69520288efd ("scsi: ufs: ufs-renesas: Add support for Renesas R-Car UFS controller") Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20230803081812.1446282-1-yoshihiro.shimoda.uh@renesas.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-renesas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-renesas.c b/drivers/ufs/host/ufs-renesas.c index f8a5e79ed3b4..ab0652d8705a 100644 --- a/drivers/ufs/host/ufs-renesas.c +++ b/drivers/ufs/host/ufs-renesas.c @@ -359,7 +359,7 @@ static int ufs_renesas_init(struct ufs_hba *hba) { struct ufs_renesas_priv *priv; - priv = devm_kmalloc(hba->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(hba->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; ufshcd_set_variant(hba, priv); -- cgit v1.2.3 From 8eebf0e84f0614cebc7347f7bbccba4056d77d42 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 3 Aug 2023 14:19:32 -0700 Subject: scsi: lpfc: Remove reftag check in DIF paths When preparing protection DIF I/O for DMA, the driver obtains reference tags from scsi_prot_ref_tag(). Previously, there was a wrong assumption that an all 0xffffffff value meant error and thus the driver failed the I/O. This patch removes the evaluation code and accepts whatever the upper layer returns. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230803211932.155745-1-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a62e091894f6..d26941b131fd 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -109,8 +109,6 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, } } -#define LPFC_INVALID_REFTAG ((u32)-1) - /** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread * @phba: The Hba for which this call is being executed. @@ -978,8 +976,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgpe = scsi_prot_sglist(sc); lba = scsi_prot_ref_tag(sc); - if (lba == LPFC_INVALID_REFTAG) - return 0; /* First check if we need to match the LBA */ if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { @@ -1560,8 +1556,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* extract some info from the scsi command for pde*/ reftag = scsi_prot_ref_tag(sc); - if (reftag == LPFC_INVALID_REFTAG) - goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -1723,8 +1717,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* extract some info from the scsi command */ blksize = scsi_prot_interval(sc); reftag = scsi_prot_ref_tag(sc); - if (reftag == LPFC_INVALID_REFTAG) - goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -1953,8 +1945,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* extract some info from the scsi command for pde*/ reftag = scsi_prot_ref_tag(sc); - if (reftag == LPFC_INVALID_REFTAG) - goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -2154,8 +2144,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* extract some info from the scsi command */ blksize = scsi_prot_interval(sc); reftag = scsi_prot_ref_tag(sc); - if (reftag == LPFC_INVALID_REFTAG) - goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -2746,8 +2734,6 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) src = (struct scsi_dif_tuple *)sg_virt(sgpe); start_ref_tag = scsi_prot_ref_tag(cmd); - if (start_ref_tag == LPFC_INVALID_REFTAG) - goto out; start_app_tag = src->app_tag; len = sgpe->length; while (src && protsegcnt) { @@ -3493,11 +3479,11 @@ err: scsi_cmnd->sc_data_direction); lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "9084 Cannot setup S/G List for HBA" - "IO segs %d/%d SGL %d SCSI %d: %d %d\n", + "9084 Cannot setup S/G List for HBA " + "IO segs %d/%d SGL %d SCSI %d: %d %d %d\n", lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, phba->cfg_total_seg_cnt, phba->cfg_sg_seg_cnt, - prot_group_type, num_sge); + prot_group_type, num_sge, ret); lpfc_cmd->seg_cnt = 0; lpfc_cmd->prot_seg_cnt = 0; -- cgit v1.2.3 From dd64f80587190265ca8a0f4be6c64c2fda6d3ac2 Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Wed, 26 Jul 2023 12:56:55 +0000 Subject: scsi: qedi: Fix potential deadlock on &qedi_percpu->p_work_lock As &qedi_percpu->p_work_lock is acquired by hard IRQ qedi_msix_handler(), other acquisitions of the same lock under process context should disable IRQ, otherwise deadlock could happen if the IRQ preempts the execution while the lock is held in process context on the same CPU. qedi_cpu_offline() is one such function which acquires the lock in process context. [Deadlock Scenario] qedi_cpu_offline() ->spin_lock(&p->p_work_lock) ->qedi_msix_handler() ->edi_process_completions() ->spin_lock_irqsave(&p->p_work_lock, flags); (deadlock here) This flaw was found by an experimental static analysis tool I am developing for IRQ-related deadlocks. The tentative patch fix the potential deadlock by spin_lock_irqsave() under process context. Signed-off-by: Chengfeng Ye Link: https://lore.kernel.org/r/20230726125655.4197-1-dg573847474@gmail.com Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 450522b204d6..77a56a136678 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1976,8 +1976,9 @@ static int qedi_cpu_offline(unsigned int cpu) struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); struct qedi_work *work, *tmp; struct task_struct *thread; + unsigned long flags; - spin_lock_bh(&p->p_work_lock); + spin_lock_irqsave(&p->p_work_lock, flags); thread = p->iothread; p->iothread = NULL; @@ -1988,7 +1989,7 @@ static int qedi_cpu_offline(unsigned int cpu) kfree(work); } - spin_unlock_bh(&p->p_work_lock); + spin_unlock_irqrestore(&p->p_work_lock, flags); if (thread) kthread_stop(thread); return 0; -- cgit v1.2.3 From 1516ee035df32115197cd93ae3619dba7b020986 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Mon, 7 Aug 2023 15:07:25 +0530 Subject: scsi: qedi: Fix firmware halt over suspend and resume While performing certain power-off sequences, PCI drivers are called to suspend and resume their underlying devices through PCI PM (power management) interface. However the hardware does not support PCI PM suspend/resume operations so system wide suspend/resume leads to bad MFW (management firmware) state which causes various follow-up errors in driver when communicating with the device/firmware. To fix this driver implements PCI PM suspend handler to indicate unsupported operation to the PCI subsystem explicitly, thus avoiding system to go into suspended/standby mode. Fixes: ace7f46ba5fd ("scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework.") Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230807093725.46829-2-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 77a56a136678..cd0180b1f5b9 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -69,6 +69,7 @@ static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); static void qedi_recovery_handler(struct work_struct *work); static void qedi_schedule_hw_err_handler(void *dev, enum qed_hw_err_type err_type); +static int qedi_suspend(struct pci_dev *pdev, pm_message_t state); static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) { @@ -2511,6 +2512,22 @@ static void qedi_shutdown(struct pci_dev *pdev) __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); } +static int qedi_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct qedi_ctx *qedi; + + if (!pdev) { + QEDI_ERR(NULL, "pdev is NULL.\n"); + return -ENODEV; + } + + qedi = pci_get_drvdata(pdev); + + QEDI_ERR(&qedi->dbg_ctx, "%s: Device does not support suspend operation\n", __func__); + + return -EPERM; +} + static int __qedi_probe(struct pci_dev *pdev, int mode) { struct qedi_ctx *qedi; @@ -2869,6 +2886,7 @@ static struct pci_driver qedi_pci_driver = { .remove = qedi_remove, .shutdown = qedi_shutdown, .err_handler = &qedi_err_handler, + .suspend = qedi_suspend, }; static int __init qedi_init(void) -- cgit v1.2.3 From ef222f551e7c4e2008fc442ffc9edcd1a7fd8f63 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Mon, 7 Aug 2023 15:07:24 +0530 Subject: scsi: qedf: Fix firmware halt over suspend and resume While performing certain power-off sequences, PCI drivers are called to suspend and resume their underlying devices through PCI PM (power management) interface. However the hardware does not support PCI PM suspend/resume operations so system wide suspend/resume leads to bad MFW (management firmware) state which causes various follow-up errors in driver when communicating with the device/firmware. To fix this driver implements PCI PM suspend handler to indicate unsupported operation to the PCI subsystem explicitly, thus avoiding system to go into suspended/standby mode. Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.") Signed-off-by: Saurav Kashyap Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230807093725.46829-1-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 2a31ddc99dde..7825765c936c 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -31,6 +31,7 @@ static void qedf_remove(struct pci_dev *pdev); static void qedf_shutdown(struct pci_dev *pdev); static void qedf_schedule_recovery_handler(void *dev); static void qedf_recovery_handler(struct work_struct *work); +static int qedf_suspend(struct pci_dev *pdev, pm_message_t state); /* * Driver module parameters. @@ -3271,6 +3272,7 @@ static struct pci_driver qedf_pci_driver = { .probe = qedf_probe, .remove = qedf_remove, .shutdown = qedf_shutdown, + .suspend = qedf_suspend, }; static int __qedf_probe(struct pci_dev *pdev, int mode) @@ -4000,6 +4002,22 @@ static void qedf_shutdown(struct pci_dev *pdev) __qedf_remove(pdev, QEDF_MODE_NORMAL); } +static int qedf_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct qedf_ctx *qedf; + + if (!pdev) { + QEDF_ERR(NULL, "pdev is NULL.\n"); + return -ENODEV; + } + + qedf = pci_get_drvdata(pdev); + + QEDF_ERR(&qedf->dbg_ctx, "%s: Device does not support suspend operation\n", __func__); + + return -EPERM; +} + /* * Recovery handler code */ -- cgit v1.2.3 From 59eeb232940515590de513b997539ef495faca9a Mon Sep 17 00:00:00 2001 From: Andrew Kanner Date: Thu, 3 Aug 2023 20:59:48 +0200 Subject: drivers: net: prevent tun_build_skb() to exceed the packet size limit Using the syzkaller repro with reduced packet size it was discovered that XDP_PACKET_HEADROOM is not checked in tun_can_build_skb(), although pad may be incremented in tun_build_skb(). This may end up with exceeding the PAGE_SIZE limit in tun_build_skb(). Jason Wang proposed to count XDP_PACKET_HEADROOM always (e.g. without rcu_access_pointer(tun->xdp_prog)) in tun_can_build_skb() since there's a window during which XDP program might be attached between tun_can_build_skb() and tun_build_skb(). Fixes: 7df13219d757 ("tun: reserve extra headroom only when XDP is set") Link: https://syzkaller.appspot.com/bug?extid=f817490f5bd20541b90a Signed-off-by: Andrew Kanner Link: https://lore.kernel.org/r/20230803185947.2379988-1-andrew.kanner@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 25f0191df00b..100339bc8b04 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1594,7 +1594,7 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile, if (zerocopy) return false; - if (SKB_DATA_ALIGN(len + TUN_RX_PAD) + + if (SKB_DATA_ALIGN(len + TUN_RX_PAD + XDP_PACKET_HEADROOM) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE) return false; -- cgit v1.2.3 From d14eea09edf427fa36bd446f4a3271f99164202f Mon Sep 17 00:00:00 2001 From: Andrew Kanner Date: Thu, 3 Aug 2023 21:03:18 +0200 Subject: net: core: remove unnecessary frame_sz check in bpf_xdp_adjust_tail() Syzkaller reported the following issue: ======================================= Too BIG xdp->frame_sz = 131072 WARNING: CPU: 0 PID: 5020 at net/core/filter.c:4121 ____bpf_xdp_adjust_tail net/core/filter.c:4121 [inline] WARNING: CPU: 0 PID: 5020 at net/core/filter.c:4121 bpf_xdp_adjust_tail+0x466/0xa10 net/core/filter.c:4103 ... Call Trace: bpf_prog_4add87e5301a4105+0x1a/0x1c __bpf_prog_run include/linux/filter.h:600 [inline] bpf_prog_run_xdp include/linux/filter.h:775 [inline] bpf_prog_run_generic_xdp+0x57e/0x11e0 net/core/dev.c:4721 netif_receive_generic_xdp net/core/dev.c:4807 [inline] do_xdp_generic+0x35c/0x770 net/core/dev.c:4866 tun_get_user+0x2340/0x3ca0 drivers/net/tun.c:1919 tun_chr_write_iter+0xe8/0x210 drivers/net/tun.c:2043 call_write_iter include/linux/fs.h:1871 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x650/0xe40 fs/read_write.c:584 ksys_write+0x12f/0x250 fs/read_write.c:637 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x38/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd xdp->frame_sz > PAGE_SIZE check was introduced in commit c8741e2bfe87 ("xdp: Allow bpf_xdp_adjust_tail() to grow packet size"). But Jesper Dangaard Brouer noted that after introducing the xdp_init_buff() which all XDP driver use - it's safe to remove this check. The original intend was to catch cases where XDP drivers have not been updated to use xdp.frame_sz, but that is not longer a concern (since xdp_init_buff). Running the initial syzkaller repro it was discovered that the contiguous physical memory allocation is used for both xdp paths in tun_get_user(), e.g. tun_build_skb() and tun_alloc_skb(). It was also stated by Jesper Dangaard Brouer that XDP can work on higher order pages, as long as this is contiguous physical memory (e.g. a page). Reported-and-tested-by: syzbot+f817490f5bd20541b90a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/000000000000774b9205f1d8a80d@google.com/T/ Link: https://syzkaller.appspot.com/bug?extid=f817490f5bd20541b90a Link: https://lore.kernel.org/all/20230725155403.796-1-andrew.kanner@gmail.com/T/ Fixes: 43b5169d8355 ("net, xdp: Introduce xdp_init_buff utility routine") Signed-off-by: Andrew Kanner Acked-by: Jesper Dangaard Brouer Acked-by: Jason Wang Link: https://lore.kernel.org/r/20230803190316.2380231-1-andrew.kanner@gmail.com Signed-off-by: Jakub Kicinski --- net/core/filter.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 06ba0e56e369..28a59596987a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4116,12 +4116,6 @@ BPF_CALL_2(bpf_xdp_adjust_tail, struct xdp_buff *, xdp, int, offset) if (unlikely(data_end > data_hard_end)) return -EINVAL; - /* ALL drivers MUST init xdp->frame_sz, chicken check below */ - if (unlikely(xdp->frame_sz > PAGE_SIZE)) { - WARN_ONCE(1, "Too BIG xdp->frame_sz = %d\n", xdp->frame_sz); - return -EINVAL; - } - if (unlikely(data_end < xdp->data + ETH_HLEN)) return -EINVAL; -- cgit v1.2.3 From 2aa71b4b294ee2c3041d085404cea914be9b3225 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 4 Aug 2023 12:12:20 +0200 Subject: net: marvell: prestera: fix handling IPv4 routes with nhid Fix handling IPv4 routes referencing a nexthop via its id by replacing calls to fib_info_nh() with fib_info_nhc(). Trying to add an IPv4 route referencing a nextop via nhid: $ ip link set up swp5 $ ip a a 10.0.0.1/24 dev swp5 $ ip nexthop add dev swp5 id 20 via 10.0.0.2 $ ip route add 10.0.1.0/24 nhid 20 triggers warnings when trying to handle the route: [ 528.805763] ------------[ cut here ]------------ [ 528.810437] WARNING: CPU: 3 PID: 53 at include/net/nexthop.h:468 __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 528.820434] Modules linked in: prestera_pci act_gact act_police sch_ingress cls_u32 cls_flower prestera arm64_delta_tn48m_dn_led(O) arm64_delta_tn48m_dn_cpld(O) [last unloaded: prestera_pci] [ 528.837485] CPU: 3 PID: 53 Comm: kworker/u8:3 Tainted: G O 6.4.5 #1 [ 528.845178] Hardware name: delta,tn48m-dn (DT) [ 528.849641] Workqueue: prestera_ordered __prestera_router_fib_event_work [prestera] [ 528.857352] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 528.864347] pc : __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 528.870135] lr : prestera_k_arb_fib_evt+0xb20/0xd50 [prestera] [ 528.876007] sp : ffff80000b20bc90 [ 528.879336] x29: ffff80000b20bc90 x28: 0000000000000000 x27: ffff0001374d3a48 [ 528.886510] x26: ffff000105604000 x25: ffff000134af8a28 x24: ffff0001374d3800 [ 528.893683] x23: ffff000101c89148 x22: ffff000101c89000 x21: ffff000101c89200 [ 528.900855] x20: ffff00013641fda0 x19: ffff800009d01088 x18: 0000000000000059 [ 528.908027] x17: 0000000000000277 x16: 0000000000000000 x15: 0000000000000000 [ 528.915198] x14: 0000000000000003 x13: 00000000000fe400 x12: 0000000000000000 [ 528.922371] x11: 0000000000000002 x10: 0000000000000aa0 x9 : ffff8000013d2020 [ 528.929543] x8 : 0000000000000018 x7 : 000000007b1703f8 x6 : 000000001ca72f86 [ 528.936715] x5 : 0000000033399ea7 x4 : 0000000000000000 x3 : ffff0001374d3acc [ 528.943886] x2 : 0000000000000000 x1 : ffff00010200de00 x0 : ffff000134ae3f80 [ 528.951058] Call trace: [ 528.953516] __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 528.958952] __prestera_router_fib_event_work+0x100/0x158 [prestera] [ 528.965348] process_one_work+0x208/0x488 [ 528.969387] worker_thread+0x4c/0x430 [ 528.973068] kthread+0x120/0x138 [ 528.976313] ret_from_fork+0x10/0x20 [ 528.979909] ---[ end trace 0000000000000000 ]--- [ 528.984998] ------------[ cut here ]------------ [ 528.989645] WARNING: CPU: 3 PID: 53 at include/net/nexthop.h:468 __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 528.999628] Modules linked in: prestera_pci act_gact act_police sch_ingress cls_u32 cls_flower prestera arm64_delta_tn48m_dn_led(O) arm64_delta_tn48m_dn_cpld(O) [last unloaded: prestera_pci] [ 529.016676] CPU: 3 PID: 53 Comm: kworker/u8:3 Tainted: G W O 6.4.5 #1 [ 529.024368] Hardware name: delta,tn48m-dn (DT) [ 529.028830] Workqueue: prestera_ordered __prestera_router_fib_event_work [prestera] [ 529.036539] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 529.043533] pc : __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 529.049318] lr : __prestera_k_arb_fc_apply+0x280/0x2f8 [prestera] [ 529.055452] sp : ffff80000b20bc60 [ 529.058781] x29: ffff80000b20bc60 x28: 0000000000000000 x27: ffff0001374d3a48 [ 529.065953] x26: ffff000105604000 x25: ffff000134af8a28 x24: ffff0001374d3800 [ 529.073126] x23: ffff000101c89148 x22: ffff000101c89148 x21: ffff00013641fda0 [ 529.080299] x20: ffff000101c89000 x19: ffff000101c89020 x18: 0000000000000059 [ 529.087471] x17: 0000000000000277 x16: 0000000000000000 x15: 0000000000000000 [ 529.094642] x14: 0000000000000003 x13: 00000000000fe400 x12: 0000000000000000 [ 529.101814] x11: 0000000000000002 x10: 0000000000000aa0 x9 : ffff8000013cee80 [ 529.108985] x8 : 0000000000000018 x7 : 000000007b1703f8 x6 : 0000000000000018 [ 529.116157] x5 : 00000000d3497eb6 x4 : ffff000105604081 x3 : 000000008e979557 [ 529.123329] x2 : 0000000000000000 x1 : ffff00010200de00 x0 : ffff000134ae3f80 [ 529.130501] Call trace: [ 529.132958] __prestera_fi_is_direct+0x2c/0x68 [prestera] [ 529.138394] prestera_k_arb_fib_evt+0x6b8/0xd50 [prestera] [ 529.143918] __prestera_router_fib_event_work+0x100/0x158 [prestera] [ 529.150313] process_one_work+0x208/0x488 [ 529.154348] worker_thread+0x4c/0x430 [ 529.158030] kthread+0x120/0x138 [ 529.161274] ret_from_fork+0x10/0x20 [ 529.164867] ---[ end trace 0000000000000000 ]--- and results in a non offloaded route: $ ip route 10.0.0.0/24 dev swp5 proto kernel scope link src 10.0.0.1 rt_trap 10.0.1.0/24 nhid 20 via 10.0.0.2 dev swp5 rt_trap When creating a route referencing a nexthop via its ID, the nexthop will be stored in a separate nh pointer instead of the array of nexthops in the fib_info struct. This causes issues since fib_info_nh() only handles the nexthops array, but not the separate nh pointer, and will loudly WARN about it. In contrast fib_info_nhc() handles both, but returns a fib_nh_common pointer instead of a fib_nh pointer. Luckily we only ever access fields from the fib_nh_common parts, so we can just replace all instances of fib_info_nh() with fib_info_nhc() and access the fields via their fib_nh_common names. This allows handling IPv4 routes with an external nexthop, and they now get offloaded as expected: $ ip route 10.0.0.0/24 dev swp5 proto kernel scope link src 10.0.0.1 rt_trap 10.0.1.0/24 nhid 20 via 10.0.0.2 dev swp5 offload rt_offload Fixes: 396b80cb5cc8 ("net: marvell: prestera: Add neighbour cache accounting") Signed-off-by: Jonas Gorski Acked-by: Elad Nachman Link: https://lore.kernel.org/r/20230804101220.247515-1-jonas.gorski@bisdn.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/prestera/prestera_router.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c index a9a1028cb17b..de317179a7dc 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_router.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c @@ -166,11 +166,11 @@ prestera_util_neigh2nc_key(struct prestera_switch *sw, struct neighbour *n, static bool __prestera_fi_is_direct(struct fib_info *fi) { - struct fib_nh *fib_nh; + struct fib_nh_common *fib_nhc; if (fib_info_num_path(fi) == 1) { - fib_nh = fib_info_nh(fi, 0); - if (fib_nh->fib_nh_gw_family == AF_UNSPEC) + fib_nhc = fib_info_nhc(fi, 0); + if (fib_nhc->nhc_gw_family == AF_UNSPEC) return true; } @@ -261,7 +261,7 @@ static bool __prestera_util_kern_n_is_reachable_v4(u32 tb_id, __be32 *addr, struct net_device *dev) { - struct fib_nh *fib_nh; + struct fib_nh_common *fib_nhc; struct fib_result res; bool reachable; @@ -269,8 +269,8 @@ __prestera_util_kern_n_is_reachable_v4(u32 tb_id, __be32 *addr, if (!prestera_util_kern_get_route(&res, tb_id, addr)) if (prestera_fi_is_direct(res.fi)) { - fib_nh = fib_info_nh(res.fi, 0); - if (dev == fib_nh->fib_nh_dev) + fib_nhc = fib_info_nhc(res.fi, 0); + if (dev == fib_nhc->nhc_dev) reachable = true; } @@ -324,7 +324,7 @@ prestera_kern_fib_info_nhc(struct fib_notifier_info *info, int n) if (info->family == AF_INET) { fen4_info = container_of(info, struct fib_entry_notifier_info, info); - return &fib_info_nh(fen4_info->fi, n)->nh_common; + return fib_info_nhc(fen4_info->fi, n); } else if (info->family == AF_INET6) { fen6_info = container_of(info, struct fib6_entry_notifier_info, info); -- cgit v1.2.3 From 39163d5479285a36522b6e8f9cc568cc4987db08 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 21 Mar 2023 23:17:58 -0700 Subject: x86/vdso: Choose the right GDT_ENTRY_CPUNODE for 32-bit getcpu() on 64-bit kernel The vDSO getcpu() reads CPU ID from the GDT_ENTRY_CPUNODE entry when the RDPID instruction is not available. And GDT_ENTRY_CPUNODE is defined as 28 on 32-bit Linux kernel and 15 on 64-bit. But the 32-bit getcpu() on 64-bit Linux kernel is compiled with 32-bit Linux kernel GDT_ENTRY_CPUNODE, i.e., 28, beyond the 64-bit Linux kernel GDT limit. Thus, it just fails _silently_. When BUILD_VDSO32_64 is defined, choose the 64-bit Linux kernel GDT definitions to compile the 32-bit getcpu(). Fixes: 877cff5296faa6e ("x86/vdso: Fake 32bit VDSO build on 64bit compile for vgetcpu") Reported-by: kernel test robot Reported-by: Shan Kang Signed-off-by: Xin Li Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20230322061758.10639-1-xin3.li@intel.com Link: https://lore.kernel.org/oe-lkp/202303020903.b01fd1de-yujie.liu@intel.com --- arch/x86/include/asm/segment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 794f69625780..9d6411c65920 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -56,7 +56,7 @@ #define GDT_ENTRY_INVALID_SEG 0 -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(BUILD_VDSO32_64) /* * The layout of the per-CPU GDT under Linux: * -- cgit v1.2.3 From d5712cd22b9cf109fded1b7f178f4c1888c8b84b Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sat, 5 Aug 2023 12:18:13 +0200 Subject: drm/nouveau/disp: Revert a NULL check inside nouveau_connector_get_modes The original commit adding that check tried to protect the kenrel against a potential invalid NULL pointer access. However we call nouveau_connector_detect_depth once without a native_mode set on purpose for non LVDS connectors and this broke DP support in a few cases. Cc: Olaf Skibbe Cc: Lyude Paul Closes: https://gitlab.freedesktop.org/drm/nouveau/-/issues/238 Closes: https://gitlab.freedesktop.org/drm/nouveau/-/issues/245 Fixes: 20a2ce87fbaf8 ("drm/nouveau/dp: check for NULL nv_connector->native_mode") Signed-off-by: Karol Herbst Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20230805101813.2603989-1-kherbst@redhat.com --- drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index f75c6f09dd2a..a2e0033e8a26 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -967,7 +967,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) /* Determine display colour depth for everything except LVDS now, * DP requires this before mode_valid() is called. */ - if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode) + if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) nouveau_connector_detect_depth(connector); /* Find the native mode if this is a digital panel, if we didn't -- cgit v1.2.3 From 07d698324110339b420deebab7a7805815340b4f Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Wed, 2 Aug 2023 18:34:30 +0200 Subject: wifi: brcm80211: handle params_v1 allocation failure Return -ENOMEM from brcmf_run_escan() if kzalloc() fails for v1 params. Fixes: 398ce273d6b1 ("wifi: brcmfmac: cfg80211: Add support for scan params v2") Signed-off-by: Petr Tesarik Link: https://lore.kernel.org/r/20230802163430.1656-1-petrtesarik@huaweicloud.com Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index de8a2e27f49c..2a90bb24ba77 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1456,6 +1456,10 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE; params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE; params_v1 = kzalloc(params_size, GFP_KERNEL); + if (!params_v1) { + err = -ENOMEM; + goto exit_params; + } params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); brcmf_scan_params_v2_to_v1(¶ms->params_v2_le, ¶ms_v1->params_le); kfree(params); @@ -1473,6 +1477,7 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, bphy_err(drvr, "error (%d)\n", err); } +exit_params: kfree(params); exit: return err; -- cgit v1.2.3 From 6a67fe45fe3fffb0721ba068e21103b94a1e57a0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 4 Aug 2023 17:24:37 -0500 Subject: MAINTAINERS: Update entry for rtl8187 As Herton Ronaldo Krzesinski is no longer active, remove him as maintainer for rtl8187. The git tree entry is also removed. Signed-off-by: Larry Finger Link: https://lore.kernel.org/r/20230804222438.16076-2-Larry.Finger@lwfinger.net Signed-off-by: Johannes Berg --- MAINTAINERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 71edae152e3a..af4913fbade4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18498,13 +18498,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g F: drivers/net/wireless/realtek/rtl818x/rtl8180/ RTL8187 WIRELESS DRIVER -M: Herton Ronaldo Krzesinski -M: Hin-Tak Leung +M: Hin-Tak Leung M: Larry Finger L: linux-wireless@vger.kernel.org S: Maintained W: https://wireless.wiki.kernel.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git F: drivers/net/wireless/realtek/rtl818x/rtl8187/ RTL8XXXU WIRELESS DRIVER (rtl8xxxu) -- cgit v1.2.3 From 017e9420c1ca19bc169e20fa749709723eaf1eb7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 4 Aug 2023 17:24:38 -0500 Subject: MAINTAINERS: Remove tree entry for rtl8180 This entry is not needed. Remove it. Signed-off-by: Larry Finger Link: https://lore.kernel.org/r/20230804222438.16076-3-Larry.Finger@lwfinger.net Signed-off-by: Johannes Berg --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index af4913fbade4..08396bdd41b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18494,7 +18494,6 @@ RTL8180 WIRELESS DRIVER L: linux-wireless@vger.kernel.org S: Orphan W: https://wireless.wiki.kernel.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git F: drivers/net/wireless/realtek/rtl818x/rtl8180/ RTL8187 WIRELESS DRIVER -- cgit v1.2.3 From b74bb07cdab6859e1a3fc9fe7351052176322ddf Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 8 Aug 2023 08:54:26 +0800 Subject: wifi: rtw89: fix 8852AE disconnection caused by RX full flags RX full flags are raised if certain types of RX FIFO are full, and then drop all following MPDU of AMPDU. In order to resume to receive MPDU when RX FIFO becomes available, we clear the register bits by the commit a0d99ebb3ecd ("wifi: rtw89: initialize DMA of CMAC"). But, 8852AE needs more settings to support this. To quickly fix disconnection problem, revert the behavior as before. Fixes: a0d99ebb3ecd ("wifi: rtw89: initialize DMA of CMAC") Reported-by: Damian B Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217710 Cc: Signed-off-by: Ping-Ke Shih Tested-by: Damian B Link: https://lore.kernel.org/r/20230808005426.5327-1-pkshih@realtek.com Signed-off-by: Johannes Berg --- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b114babec698..c93e6250cb8b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2524,7 +2524,7 @@ static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx) u32 reg; int ret; - if (chip_id != RTL8852A && chip_id != RTL8852B) + if (chip_id != RTL8852B) return 0; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); -- cgit v1.2.3 From 5fb9a9fb71a33be61d7d8e8ba4597bfb18d604d0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 22 Jun 2023 18:59:19 +0200 Subject: wifi: cfg80211: fix sband iftype data lookup for AP_VLAN AP_VLAN interfaces are virtual, so doesn't really exist as a type for capabilities. When passed in as a type, AP is the one that's really intended. Fixes: c4cbaf7973a7 ("cfg80211: Add support for HE") Signed-off-by: Felix Fietkau Link: https://lore.kernel.org/r/20230622165919.46841-1-nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7c7d03aa9d06..d6fa7c8767ad 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -562,6 +562,9 @@ ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband, if (WARN_ON(iftype >= NL80211_IFTYPE_MAX)) return NULL; + if (iftype == NL80211_IFTYPE_AP_VLAN) + iftype = NL80211_IFTYPE_AP; + for (i = 0; i < sband->n_iftype_data; i++) { const struct ieee80211_sband_iftype_data *data = &sband->iftype_data[i]; -- cgit v1.2.3 From 94c40dbbffa11bec54b5ca74df1c5bb0f52995b9 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Sat, 5 Aug 2023 19:22:16 +0300 Subject: ASoC: amd: acp3x-rt5682-max9836: Configure jack as not detecting Line Out The RT5682, RT1015 and RT1015p codecs used in this driver do not seem capable of distinguishing Line Out connections from Headphone, but the driver configures its jack object as if it can. Remove the wrong value from the jack creation call to avoid any confusion. Signed-off-by: Alper Nebi Yasak Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Link: https://lore.kernel.org/r/20230805162216.441410-1-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp3x-rt5682-max9836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 3bf7e1e83c36..28ad5f5b9a76 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -98,7 +98,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); ret = snd_soc_card_jack_new_pins(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &pco_jack, -- cgit v1.2.3 From c0b067588a4836b762cfc6a4c83f122ca1dbb93a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 1 Aug 2023 18:42:47 -0300 Subject: Revert "perf report: Append inlines to non-DWARF callchains" This reverts commit 46d21ec067490ab9cdcc89b9de5aae28786a8b8e. The tests were made with a specific workload, further tests on a recently updated fedora 38 system with a system wide perf.data file shows 'perf report' taking excessive time resolving inlines in vmlinux, so lets revert this until a full investigation and improvement on the addr2line support code is made. Reported-by: Jesper Dangaard Brouer Acked-by: Artem Savkov Tested-by: Jesper Dangaard Brouer Cc: Andrii Nakryiko Cc: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Milian Wolff Cc: Peter Zijlstra Link: https://lore.kernel.org/r/ZMl8VyhdwhClTM5g@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 4e62843d51b7..f4cb41ee23cd 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -45,7 +45,6 @@ static void __machine__remove_thread(struct machine *machine, struct thread_rb_node *nd, struct thread *th, bool lock); -static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip); static struct dso *machine__kernel_dso(struct machine *machine) { @@ -2385,10 +2384,6 @@ static int add_callchain_ip(struct thread *thread, ms.maps = maps__get(al.maps); ms.map = map__get(al.map); ms.sym = al.sym; - - if (!branch && append_inlines(cursor, &ms, ip) == 0) - goto out; - srcline = callchain_srcline(&ms, al.addr); err = callchain_cursor_append(cursor, ip, &ms, branch, flags, nr_loop_iter, -- cgit v1.2.3 From 8cdd4aeff2e858c95bb088409028893cfb4e53d4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 7 Aug 2023 10:41:42 -0300 Subject: tools arch x86: Sync the msr-index.h copy with the kernel sources To pick up the changes from these csets: 522b1d69219d8f08 ("x86/cpu/amd: Add a Zenbleed fix") That cause no changes to tooling: $ tools/perf/trace/beauty/tracepoints/x86_msr.sh > before $ cp arch/x86/include/asm/msr-index.h tools/arch/x86/include/asm/msr-index.h $ tools/perf/trace/beauty/tracepoints/x86_msr.sh > after $ diff -u before after $ Just silences this perf build warning: Warning: Kernel ABI header differences: diff -u tools/arch/x86/include/asm/msr-index.h arch/x86/include/asm/msr-index.h Cc: Adrian Hunter Cc: Borislav Petkov (AMD) Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZND17H7BI4ariERn@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/msr-index.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 3aedae61af4f..a00a53e15ab7 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -545,6 +545,7 @@ #define MSR_AMD64_DE_CFG 0xc0011029 #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1 #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT) +#define MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT 9 #define MSR_AMD64_BU_CFG2 0xc001102a #define MSR_AMD64_IBSFETCHCTL 0xc0011030 -- cgit v1.2.3 From 9a8fa00dad3c7b260071f2f220cfb00505372c40 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 3 Jul 2023 14:25:53 +0530 Subject: cpuidle: dt_idle_genpd: Add helper function to remove genpd topology Genpd parent and child domain topology created using dt_idle_pd_init_topology() needs to be removed during error cases. Add new helper function dt_idle_pd_remove_topology() for same. Cc: stable@vger.kernel.org Reviewed-by: Ulf Hanssson Signed-off-by: Maulik Shah Signed-off-by: Ulf Hansson --- drivers/cpuidle/dt_idle_genpd.c | 24 ++++++++++++++++++++++++ drivers/cpuidle/dt_idle_genpd.h | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/cpuidle/dt_idle_genpd.c b/drivers/cpuidle/dt_idle_genpd.c index b37165514d4e..1af63c189039 100644 --- a/drivers/cpuidle/dt_idle_genpd.c +++ b/drivers/cpuidle/dt_idle_genpd.c @@ -152,6 +152,30 @@ int dt_idle_pd_init_topology(struct device_node *np) return 0; } +int dt_idle_pd_remove_topology(struct device_node *np) +{ + struct device_node *node; + struct of_phandle_args child, parent; + int ret; + + for_each_child_of_node(np, node) { + if (of_parse_phandle_with_args(node, "power-domains", + "#power-domain-cells", 0, &parent)) + continue; + + child.np = node; + child.args_count = 0; + ret = of_genpd_remove_subdomain(&parent, &child); + of_node_put(parent.np); + if (ret) { + of_node_put(node); + return ret; + } + } + + return 0; +} + struct device *dt_idle_attach_cpu(int cpu, const char *name) { struct device *dev; diff --git a/drivers/cpuidle/dt_idle_genpd.h b/drivers/cpuidle/dt_idle_genpd.h index a95483d08a02..3be1f70f55b5 100644 --- a/drivers/cpuidle/dt_idle_genpd.h +++ b/drivers/cpuidle/dt_idle_genpd.h @@ -14,6 +14,8 @@ struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np, int dt_idle_pd_init_topology(struct device_node *np); +int dt_idle_pd_remove_topology(struct device_node *np); + struct device *dt_idle_attach_cpu(int cpu, const char *name); void dt_idle_detach_cpu(struct device *dev); @@ -36,6 +38,11 @@ static inline int dt_idle_pd_init_topology(struct device_node *np) return 0; } +static inline int dt_idle_pd_remove_topology(struct device_node *np) +{ + return 0; +} + static inline struct device *dt_idle_attach_cpu(int cpu, const char *name) { return NULL; -- cgit v1.2.3 From 12acb348fa4528a4203edf1cce7a3be2c9af2279 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 3 Jul 2023 14:25:54 +0530 Subject: cpuidle: psci: Move enabling OSI mode after power domains creation A switch from OSI to PC mode is only possible if all CPUs other than the calling one are OFF, either through a call to CPU_OFF or not yet booted. Currently OSI mode is enabled before power domains are created. In cases where CPUidle states are not using hierarchical CPU topology the bail out path tries to switch back to PC mode which gets denied by firmware since other CPUs are online at this point and creates inconsistent state as firmware is in OSI mode and Linux in PC mode. This change moves enabling OSI mode after power domains are created, this would makes sure that hierarchical CPU topology is used before switching firmware to OSI mode. Cc: stable@vger.kernel.org Fixes: 70c179b49870 ("cpuidle: psci: Allow PM domain to be initialized even if no OSI mode") Signed-off-by: Maulik Shah Reviewed-by: Ulf Hansson Signed-off-by: Ulf Hansson --- drivers/cpuidle/cpuidle-psci-domain.c | 39 ++++++++++++----------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c index c2d6d9c3c930..b88af1262f1a 100644 --- a/drivers/cpuidle/cpuidle-psci-domain.c +++ b/drivers/cpuidle/cpuidle-psci-domain.c @@ -120,20 +120,6 @@ static void psci_pd_remove(void) } } -static bool psci_pd_try_set_osi_mode(void) -{ - int ret; - - if (!psci_has_osi_support()) - return false; - - ret = psci_set_osi_mode(true); - if (ret) - return false; - - return true; -} - static void psci_cpuidle_domain_sync_state(struct device *dev) { /* @@ -152,15 +138,12 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *node; - bool use_osi; + bool use_osi = psci_has_osi_support(); int ret = 0, pd_count = 0; if (!np) return -ENODEV; - /* If OSI mode is supported, let's try to enable it. */ - use_osi = psci_pd_try_set_osi_mode(); - /* * Parse child nodes for the "#power-domain-cells" property and * initialize a genpd/genpd-of-provider pair when it's found. @@ -170,33 +153,37 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev) continue; ret = psci_pd_init(node, use_osi); - if (ret) - goto put_node; + if (ret) { + of_node_put(node); + goto exit; + } pd_count++; } /* Bail out if not using the hierarchical CPU topology. */ if (!pd_count) - goto no_pd; + return 0; /* Link genpd masters/subdomains to model the CPU topology. */ ret = dt_idle_pd_init_topology(np); if (ret) goto remove_pd; + /* let's try to enable OSI. */ + ret = psci_set_osi_mode(use_osi); + if (ret) + goto remove_pd; + pr_info("Initialized CPU PM domain topology using %s mode\n", use_osi ? "OSI" : "PC"); return 0; -put_node: - of_node_put(node); remove_pd: + dt_idle_pd_remove_topology(np); psci_pd_remove(); +exit: pr_err("failed to create CPU PM domains ret=%d\n", ret); -no_pd: - if (use_osi) - psci_set_osi_mode(false); return ret; } -- cgit v1.2.3 From 1963546390ed8b649f529993a755eba0fdeb7aaa Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Wed, 2 Aug 2023 08:37:35 +0200 Subject: accel/ivpu: Add set_pages_array_wc/uc for internal buffers Buffers mapped with pgprot_writecombined() are not correctly flushed. This triggers issues on VPU access using random memory content such as MMU translation faults, invalid context descriptors being fetched and can lead to VPU FW crashes. Fixes: 647371a6609d ("accel/ivpu: Add GEM buffer object management") Cc: stable@vger.kernel.org # 6.3+ Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20230802063735.3005291-1-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 52b339aefadc..9967fcfa27ec 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -173,6 +173,9 @@ static void internal_free_pages_locked(struct ivpu_bo *bo) { unsigned int i, npages = bo->base.size >> PAGE_SHIFT; + if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) + set_pages_array_wb(bo->pages, bo->base.size >> PAGE_SHIFT); + for (i = 0; i < npages; i++) put_page(bo->pages[i]); @@ -587,6 +590,11 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) drm_clflush_pages(bo->pages, bo->base.size >> PAGE_SHIFT); + if (bo->flags & DRM_IVPU_BO_WC) + set_pages_array_wc(bo->pages, bo->base.size >> PAGE_SHIFT); + else if (bo->flags & DRM_IVPU_BO_UNCACHED) + set_pages_array_uc(bo->pages, bo->base.size >> PAGE_SHIFT); + prot = ivpu_bo_pgprot(bo, PAGE_KERNEL); bo->kvaddr = vmap(bo->pages, bo->base.size >> PAGE_SHIFT, VM_MAP, prot); if (!bo->kvaddr) { -- cgit v1.2.3 From 487ae3b42d1040b4cd5ff9754e7516b409204029 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 1 Aug 2023 13:54:52 -0700 Subject: perf stat: Don't display zero tool counts Andi reported (see link below) a regression when printing the 'duration_time' tool event, where it gets printed as "not counted" for most of the CPUs, fix it by skipping zero counts for tool events. Reported-by: Andi Kleen Signed-off-by: Ian Rogers Tested-by: Andi Kleen Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Claire Jensen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/all/ZMlrzcVrVi1lTDmn@tassilo/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/stat-display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 7329b3340f88..d45d5dcb0e2b 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -931,6 +931,11 @@ static bool should_skip_zero_counter(struct perf_stat_config *config, */ if (config->aggr_mode == AGGR_THREAD && config->system_wide) return true; + + /* Tool events have the software PMU but are only gathered on 1. */ + if (evsel__is_tool(counter)) + return true; + /* * Skip value 0 when it's an uncore event and the given aggr id * does not belong to the PMU cpumask. -- cgit v1.2.3 From 8e5c4a9fc47ab6d8e1d9cf6c1f11c90675c1d968 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 8 Aug 2023 10:17:28 +0800 Subject: ASoC: imx-audio-rpmsg: Remove redundant initialization owner in imx_audio_rpmsg_driver The module_rpmsg_driver() will set "THIS_MODULE" to driver.owner when register a rpmsg_driver driver, so it is redundant initialization to set driver.owner in the statement. Remove it for clean code. Signed-off-by: Li Zetao Link: https://lore.kernel.org/r/20230808021728.2978035-1-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audio-rpmsg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index d5234ac4b09b..289e47c03d40 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -116,7 +116,6 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = { static struct rpmsg_driver imx_audio_rpmsg_driver = { .drv.name = "imx_audio_rpmsg", - .drv.owner = THIS_MODULE, .id_table = imx_audio_rpmsg_id_table, .probe = imx_audio_rpmsg_probe, .callback = imx_audio_rpmsg_cb, -- cgit v1.2.3 From c307ca16c9bffc18dbf37ae64c71d935a2923c3a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:02 +0100 Subject: ASoC: intel: sof_sdw: Printk's should end with a newline Add the missing new lines. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index fd27e211211b..8f3329dcf706 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -524,7 +524,7 @@ int sdw_prepare(struct snd_pcm_substream *substream) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -543,7 +543,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -565,7 +565,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) } if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret); + dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); return ret; } @@ -630,7 +630,7 @@ int sdw_hw_free(struct snd_pcm_substream *substream) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -1339,7 +1339,7 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, return -EINVAL; if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, " cpu_dai_id array overflows"); + dev_err(dev, "cpu_dai_id array overflows\n"); return -EINVAL; } @@ -1490,7 +1490,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, return -ENOMEM; if (cpu_dai_index >= sdw_cpu_dai_num) { - dev_err(dev, "invalid cpu dai index %d", + dev_err(dev, "invalid cpu dai index %d\n", cpu_dai_index); return -EINVAL; } @@ -1503,12 +1503,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, * not be larger than sdw_be_num */ if (*link_index >= sdw_be_num) { - dev_err(dev, "invalid dai link index %d", *link_index); + dev_err(dev, "invalid dai link index %d\n", *link_index); return -EINVAL; } if (*cpu_id >= sdw_cpu_dai_num) { - dev_err(dev, " invalid cpu dai index %d", *cpu_id); + dev_err(dev, "invalid cpu dai index %d\n", *cpu_id); return -EINVAL; } @@ -1531,7 +1531,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { - dev_err(dev, "failed to init codec %d", codec_index); + dev_err(dev, "failed to init codec %d\n", codec_index); return ret; } @@ -1675,7 +1675,7 @@ out: endpoint = adr_link->adr_d[i].endpoints; if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x", + dev_err(dev, "invalid group id on link %x\n", adr_link->mask); continue; } @@ -1698,7 +1698,7 @@ out: &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); if (ret < 0) { - dev_err(dev, "failed to create dai link %d", link_index); + dev_err(dev, "failed to create dai link %d\n", link_index); return ret; } } -- cgit v1.2.3 From 3003ea9cb7bd6399ca9962e0b3dd0ac58b151c2e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:03 +0100 Subject: ASoC: intel: sof_sdw: Remove duplicate NULL check on adr_link get_dailink_info already checked if the adr_link pointer was NULL so there is no need to recheck later in sof_card_dai_links_create. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 8f3329dcf706..89614d08d091 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1632,10 +1632,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sdw_be_num) goto SSP; - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - for (i = 0; i < SDW_MAX_LINKS; i++) sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; -- cgit v1.2.3 From e1cfd5fef3d6eaf0ddbc54da70ddf54462b23592 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:04 +0100 Subject: ASoC: intel: sof_sdw: Check link mask validity in get_dailink_info As get_dailink_info spins through all the links anyway simply check the link masks there. This saves an extra check and means the code will fail earlier if the mask is invalid. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 89614d08d091..268629d5505c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1053,6 +1053,10 @@ static int get_dailink_info(struct device *dev, int stream; u64 adr; + /* make sure the link mask has a single bit set */ + if (!is_power_of_2(adr_link->mask)) + return -EINVAL; + for (i = 0; i < adr_link->num_adr; i++) { adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); @@ -1302,10 +1306,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; adr_d = &adr_link->adr_d[adr_index]; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; if (!adr_d->endpoints->aggregated || no_aggregation) { *cpu_dai_num = 1; @@ -1334,10 +1334,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, endpoint->group_id != *group_id) continue; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_next->mask)) - return -EINVAL; - if (index >= SDW_MAX_CPU_DAIS) { dev_err(dev, "cpu_dai_id array overflows\n"); return -EINVAL; -- cgit v1.2.3 From 87608d3e9de18331c5d3c9ecb915b0ff3d03c089 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:05 +0100 Subject: ASoC: intel: sof-sdw: Move check for valid group id to get_dailink_info Move the check for a valid group id into get_dailink_info as well. This does cause a slight change in behaviour in that the system will return an error rather than just ignoring the link with an invalid group id. There are presently no systems with invalid group ids in mainline and failing seems more appropriate since it will better highlight the code needs fixing. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 268629d5505c..b250fb7be4bf 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1074,6 +1074,11 @@ static int get_dailink_info(struct device *dev, } endpoint = adr_link->adr_d[i].endpoints; + if (endpoint->aggregated && !endpoint->group_id) { + dev_err(dev, "invalid group id on link %x\n", + adr_link->mask); + return -EINVAL; + } for (j = 0; j < codec_info->dai_num; j++) { /* count DAI number for playback and capture */ @@ -1666,11 +1671,6 @@ out: const struct snd_soc_acpi_endpoint *endpoint; endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x\n", - adr_link->mask); - continue; - } /* this group has been generated */ if (endpoint->aggregated && -- cgit v1.2.3 From 92e9f10a093529f85b7557b0627531728d89afa2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:06 +0100 Subject: ASoC: intel: sof_sdw: Add helper to create a single codec DLC Add a helper function to create a single codec DAI link component structure. This sets things up for more refactoring of the creating of the DAI links. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 80 +++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b250fb7be4bf..ba4775e77807 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1160,6 +1160,43 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, return true; } +static int fill_sdw_codec_dlc(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + struct snd_soc_dai_link_component *codec, + int codec_index, int adr_index, int dai_index) +{ + unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; + u64 adr = adr_link->adr_d[adr_index].adr; + + sdw_version = SDW_VERSION(adr); + link_id = SDW_DISCO_LINK_ID(adr); + unique_id = SDW_UNIQUE_ID(adr); + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + class_id = SDW_CLASS_ID(adr); + + if (codec_info_list[codec_index].codec_name) + codec->name = devm_kstrdup(dev, + codec_info_list[codec_index].codec_name, + GFP_KERNEL); + else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x", link_id, + mfg_id, part_id, class_id); + else + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x:%01x", link_id, + mfg_id, part_id, class_id, unique_id); + + if (!codec->name) + return -ENOMEM; + + codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; + + return 0; +} + static int create_codec_dai_name(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, @@ -1171,7 +1208,7 @@ static int create_codec_dai_name(struct device *dev, int dai_index) { int _codec_index = -1; - int i; + int i, ret; /* sanity check */ if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { @@ -1180,13 +1217,8 @@ static int create_codec_dai_name(struct device *dev, } for (i = adr_index; i < adr_link->num_adr; i++) { - unsigned int sdw_version, unique_id, mfg_id; - unsigned int link_id, part_id, class_id; int codec_index, comp_index; - char *codec_str; - u64 adr; - - adr = adr_link->adr_d[i].adr; + u64 adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); if (codec_index < 0) @@ -1197,38 +1229,12 @@ static int create_codec_dai_name(struct device *dev, } _codec_index = codec_index; - sdw_version = SDW_VERSION(adr); - link_id = SDW_DISCO_LINK_ID(adr); - unique_id = SDW_UNIQUE_ID(adr); - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - class_id = SDW_CLASS_ID(adr); - comp_index = i - adr_index + offset; - if (codec_info_list[codec_index].codec_name) { - codec[comp_index].name = - devm_kstrdup(dev, codec_info_list[codec_index].codec_name, - GFP_KERNEL); - } else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, - class_id, i)) { - codec_str = "sdw:%01x:%04x:%04x:%02x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id); - } else { - codec_str = "sdw:%01x:%04x:%04x:%02x:%01x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id, unique_id); - } - if (!codec[comp_index].name) - return -ENOMEM; - - codec[comp_index].dai_name = - codec_info_list[codec_index].dais[dai_index].dai_name; + ret = fill_sdw_codec_dlc(dev, adr_link, &codec[comp_index], + codec_index, i, dai_index); + if (ret) + return ret; codec_conf[*codec_conf_index].dlc = codec[comp_index]; codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; -- cgit v1.2.3 From c3d7e29ad82ee689b1adf5ea7806b9d06eb098c0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:07 +0100 Subject: ASoC: intel: sof_sdw: Pull device loop up into create_sdw_dailink The loops which fill the codec DAI link component structures are split across create_sdw_dailink and create_codec_dai_name. This causes the code to be rather confusing, needing to return out the function to allow the upper loop to iterate. Remove the create_codec_dai_name helper and pull its code up into create_sdw_dailink, this makes it more obvious what is happening in the code. This patch makes no functional change just hoists the code up a level. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-6-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 89 ++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ba4775e77807..5c154628236c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1197,54 +1197,6 @@ static int fill_sdw_codec_dlc(struct device *dev, return 0; } -static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link_component *codec, - int offset, - struct snd_soc_codec_conf *codec_conf, - int codec_count, - int *codec_conf_index, - int adr_index, - int dai_index) -{ - int _codec_index = -1; - int i, ret; - - /* sanity check */ - if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { - dev_err(dev, "codec_conf: out-of-bounds access requested\n"); - return -EINVAL; - } - - for (i = adr_index; i < adr_link->num_adr; i++) { - int codec_index, comp_index; - u64 adr = adr_link->adr_d[i].adr; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; - - comp_index = i - adr_index + offset; - - ret = fill_sdw_codec_dlc(dev, adr_link, &codec[comp_index], - codec_index, i, dai_index); - if (ret) - return ret; - - codec_conf[*codec_conf_index].dlc = codec[comp_index]; - codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; - - ++*codec_conf_index; - } - - return 0; -} - static int set_codec_init_func(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link *dai_links, @@ -1401,8 +1353,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int codec_num; int stream; int i = 0; + int j, k; int ret; - int k; ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, &group_id, adr_index); @@ -1417,6 +1369,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; + int _codec_index = -1; endpoints = adr_link_next->adr_d->endpoints; if (group_id && (!endpoints->aggregated || @@ -1427,11 +1380,39 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_dlc_index, - codec_conf, codec_count, codec_conf_index, - adr_index, dai_index); - if (ret < 0) - return ret; + /* sanity check */ + if (*codec_conf_index + adr_link_next->num_adr - adr_index > codec_count) { + dev_err(dev, "codec_conf: out-of-bounds access requested\n"); + return -EINVAL; + } + + for (j = adr_index; j < adr_link_next->num_adr; j++) { + int codec_index, comp_index; + u64 adr = adr_link_next->adr_d[j].adr; + + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; + if (_codec_index != -1 && codec_index != _codec_index) { + dev_dbg(dev, "Different devices on the same sdw link\n"); + break; + } + _codec_index = codec_index; + + comp_index = j - adr_index + codec_dlc_index; + + ret = fill_sdw_codec_dlc(dev, adr_link_next, + &codecs[comp_index], + codec_index, j, dai_index); + if (ret) + return ret; + + codec_conf[*codec_conf_index].dlc = codecs[comp_index]; + codec_conf[*codec_conf_index].name_prefix = + adr_link_next->adr_d[j].name_prefix; + + (*codec_conf_index)++; + } /* check next link to create codec dai in the processed group */ i++; -- cgit v1.2.3 From 0e82229fb74a26cfaf6ae3772cbdefdb643f98a5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:08 +0100 Subject: ASoC: intel: sof_sdw: Update DLC index each time one is added In create_sdw_dailink, rather than bulk updating the index into the DAI link components array, at the end of processing a link, do so each time the code adds a new component. This simplifies things slightly, as an intermediate variable is no longer needed to track the current place in the DAI link components array. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 5c154628236c..b381fb261994 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1387,7 +1387,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } for (j = adr_index; j < adr_link_next->num_adr; j++) { - int codec_index, comp_index; + int codec_index; u64 adr = adr_link_next->adr_d[j].adr; codec_index = find_codec_info_part(adr); @@ -1399,24 +1399,22 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; - comp_index = j - adr_index + codec_dlc_index; - ret = fill_sdw_codec_dlc(dev, adr_link_next, - &codecs[comp_index], + &codecs[codec_dlc_index], codec_index, j, dai_index); if (ret) return ret; - codec_conf[*codec_conf_index].dlc = codecs[comp_index]; + codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; codec_conf[*codec_conf_index].name_prefix = adr_link_next->adr_d[j].name_prefix; + codec_dlc_index++; (*codec_conf_index)++; } /* check next link to create codec dai in the processed group */ i++; - codec_dlc_index += adr_link_next->num_adr; } /* find codec info to create BE DAI */ -- cgit v1.2.3 From 59736ca62e1eeb4466ace99e167cbe7a0f9bc0fa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:09 +0100 Subject: ASoC: intel: sof_sdw: Move range check of codec_conf into inner loop There are two problems with the current range check on the codec_conf array. Firstly, adr_link_next->num_adr refers to the number of devices on the current SoundWire link, but adr_index refers to the first SoundWire link involved in the DAI link. This means that subtracting these two numbers is only meaningful on the first SoundWire link in the DAI and broken on later links. Secondly, the intention of the range check is to add the number of remaining devices on the currently link to the current index and ensure enough space remains. However, this assumes that all remaining devices on the SoundWire link will be added to the current DAI link. Ideally this would not be the case, and devices could be grouped as the user desired. Moving the range check into the inner loop both simplifies the code (no need to add and subtract offsets) and allows future refactoring such that devices on a single SoundWire link don't have to all be grouped onto a single DAI link. The check will be processed slightly more often since it is processed for each device rather each link but this is probe time and the numbers involved are very small here (4 links, likely no more than 2-4 devices per link). Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b381fb261994..0401516f35de 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1380,12 +1380,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - /* sanity check */ - if (*codec_conf_index + adr_link_next->num_adr - adr_index > codec_count) { - dev_err(dev, "codec_conf: out-of-bounds access requested\n"); - return -EINVAL; - } - for (j = adr_index; j < adr_link_next->num_adr; j++) { int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1399,6 +1393,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; + /* sanity check */ + if (*codec_conf_index >= codec_count) { + dev_err(dev, "codec_conf array overflowed\n"); + return -EINVAL; + } + ret = fill_sdw_codec_dlc(dev, adr_link_next, &codecs[codec_dlc_index], codec_index, j, dai_index); -- cgit v1.2.3 From f3eb3d45fdfd693dc004e664544f978ae8d38f48 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:10 +0100 Subject: ASoC: intel: sof_sdw: Device loop should not always start at adr_index The current loops at the top of create_sdw_dailink process the devices on each link starting from device index adr_index. But adr_index is only meaningful on the first on these SoundWire links, as it is the index of the current device on that link. This means devices will be skipped on later links. Say for example the system looks like this: SDW0 - Codec (Not Aggregated), Amp 1 (Aggregated, Group 1) SDW1 - Amp 2 (Aggregated, Group 1), Amp 3 (Aggregated, Group 1) The code should create 2 DAI links, one for the CODEC and one for the aggregated amps. It will create the DAI link for the codec no problem. When it creates the DAI link for Group 1 however, create_sdw_dailink will be called with an adr_index of 1, since that is the index of Amp 1 on SDW0. However, as the loop in create_sdw_dailink moves onto SDW1 it will again start from adr_index, skipping Amp 2. Resulting in the amp DAI link only have amps 1 and 3 in it. It is reasonable to start at adr_index on the first link, since earlier devices have by definition already been processed. However, update the code when processing later links to handle all devices. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-9-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0401516f35de..767c49022eae 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1366,6 +1366,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, return -ENOMEM; /* generate codec name on different links in the same group */ + j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; @@ -1380,7 +1381,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - for (j = adr_index; j < adr_link_next->num_adr; j++) { + /* j reset after loop, adr_index only applies to first link */ + for (; j < adr_link_next->num_adr; j++) { int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1412,6 +1414,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, codec_dlc_index++; (*codec_conf_index)++; } + j = 0; /* check next link to create codec dai in the processed group */ i++; -- cgit v1.2.3 From f82742dd479dfec7dc6a30a84f165a258c51ce09 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:11 +0100 Subject: ASoC: intel: sof_sdw: Support multiple groups on the same link The current code checks the first device on a link and assumes that all the other devices on the link will have the same endpoint aggregation status and endpoint group ID. Say for example a system looked like: SDW0 - Amp 1 (Aggregated, Group 1), Mic 1 (Aggregated, Group 2) SDW1 - Amp 2 (Aggregated, Group 1), Mic 2 (Aggregated, Group 2) The current code would create the DAI link for the aggregated amps, although it is worth noting that the only reason Mic 2 is not added is the additional check that aborts processing the link when the device changes. Then when processing the DAI link for the microphones, Mic 2 would not be added, as the check will only be done on the first device, which would be Amp 2 and thus the wrong group, causing the whole link to be skipped. Move the endpoint check to be for each device rather than the first device on each link. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-10-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 767c49022eae..357946365e76 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1288,25 +1288,24 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, } /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; - adr_next++) { - const struct snd_soc_acpi_endpoint *endpoint; - - endpoint = adr_next->adr_d->endpoints; - if (!endpoint->aggregated || - endpoint->group_id != *group_id) - continue; + for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; adr_next++) { + unsigned int link_codecs = 0; - if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, "cpu_dai_id array overflows\n"); - return -EINVAL; - } - - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; for (i = 0; i < adr_next->num_adr; i++) { if (adr_next->adr_d[i].endpoints->aggregated && adr_next->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; + link_codecs++; + } + + if (link_codecs) { + *codec_num += link_codecs; + + if (index >= SDW_MAX_CPU_DAIS) { + dev_err(dev, "cpu_dai_id array overflowed\n"); + return -EINVAL; + } + + cpu_dai_id[index++] = ffs(adr_next->mask) - 1; } } @@ -1369,20 +1368,15 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { - const struct snd_soc_acpi_endpoint *endpoints; int _codec_index = -1; - endpoints = adr_link_next->adr_d->endpoints; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - /* skip the link excluded by this processed group */ if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; /* j reset after loop, adr_index only applies to first link */ for (; j < adr_link_next->num_adr; j++) { + const struct snd_soc_acpi_endpoint *endpoints; int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1395,6 +1389,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; + endpoints = adr_link_next->adr_d[j].endpoints; + + if (group_id && (!endpoints->aggregated || + endpoints->group_id != group_id)) + continue; + /* sanity check */ if (*codec_conf_index >= codec_count) { dev_err(dev, "codec_conf array overflowed\n"); -- cgit v1.2.3 From 317dcdecaf7a42febb78c564df15fd817bf720b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:12 +0100 Subject: ASoC: intel: sof_sdw: Allow different devices on the same link If the current code encounters a new type of device on a SoundWire link, it will abort processing that link and move onto the next link. However, there is no reason to disallow this setup, it would appear this was being disallowed to work around issues introduced by only the first endpoint on each link being checked, which is now fixed. The device type shouldn't determine which DAI link it is connected to, the group ID and aggregation status should. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-11-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 357946365e76..296de5baee3d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1163,10 +1163,15 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, static int fill_sdw_codec_dlc(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, - int codec_index, int adr_index, int dai_index) + int adr_index, int dai_index) { unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; u64 adr = adr_link->adr_d[adr_index].adr; + int codec_index; + + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); @@ -1368,8 +1373,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { - int _codec_index = -1; - /* skip the link excluded by this processed group */ if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; @@ -1377,17 +1380,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, /* j reset after loop, adr_index only applies to first link */ for (; j < adr_link_next->num_adr; j++) { const struct snd_soc_acpi_endpoint *endpoints; - int codec_index; - u64 adr = adr_link_next->adr_d[j].adr; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; endpoints = adr_link_next->adr_d[j].endpoints; @@ -1403,7 +1395,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, ret = fill_sdw_codec_dlc(dev, adr_link_next, &codecs[codec_dlc_index], - codec_index, j, dai_index); + j, dai_index); if (ret) return ret; -- cgit v1.2.3 From 7f5cf19703ccb05ac4965d1cfc1422e38bec93aa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:13 +0100 Subject: ASoC: intel: sof_sdw: Simplify get_slave_info Now the first device on a link is not treated specially there is no need to have a separate loop to handle the current link over the future links, as the logic is identical. Combine this all into a single processing loop. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-12-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 296de5baee3d..f283c0d528df 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1265,57 +1265,43 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, int *codec_num, unsigned int *group_id, int adr_index) { - const struct snd_soc_acpi_adr_device *adr_d; - const struct snd_soc_acpi_link_adr *adr_next; - bool no_aggregation; - int index = 0; + bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; int i; - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - adr_d = &adr_link->adr_d[adr_index]; - - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; - if (!adr_d->endpoints->aggregated || no_aggregation) { + if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { + cpu_dai_id[0] = ffs(adr_link->mask) - 1; *cpu_dai_num = 1; *codec_num = 1; *group_id = 0; return 0; } - *group_id = adr_d->endpoints->group_id; - - /* Count endpoints with the same group_id in the adr_link */ *codec_num = 0; - for (i = 0; i < adr_link->num_adr; i++) { - if (adr_link->adr_d[i].endpoints->aggregated && - adr_link->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; - } + *cpu_dai_num = 0; + *group_id = adr_link->adr_d[adr_index].endpoints->group_id; - /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; adr_next++) { + /* Count endpoints with the same group_id in the adr_link */ + for (; adr_link && adr_link->num_adr; adr_link++) { unsigned int link_codecs = 0; - for (i = 0; i < adr_next->num_adr; i++) { - if (adr_next->adr_d[i].endpoints->aggregated && - adr_next->adr_d[i].endpoints->group_id == *group_id) + for (i = 0; i < adr_link->num_adr; i++) { + if (adr_link->adr_d[i].endpoints->aggregated && + adr_link->adr_d[i].endpoints->group_id == *group_id) link_codecs++; } if (link_codecs) { *codec_num += link_codecs; - if (index >= SDW_MAX_CPU_DAIS) { + if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { dev_err(dev, "cpu_dai_id array overflowed\n"); return -EINVAL; } - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; + cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; } } - *cpu_dai_num = index; - return 0; } -- cgit v1.2.3 From 87b56172431bc2e8c497d2f10ee8245313167bd9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Aug 2023 14:56:54 +0200 Subject: ASoC: codecs: aw88261: avoid uninitialized variable warning aw88261_reg_update() returns an unintialized error code in the success path: sound/soc/codecs/aw88261.c:651:7: error: variable 'ret' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] if (aw_dev->prof_cur != aw_dev->prof_index) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/soc/codecs/aw88261.c:660:9: note: uninitialized use occurs here return ret; ^~~ sound/soc/codecs/aw88261.c:651:3: note: remove the 'if' if its condition is always true if (aw_dev->prof_cur != aw_dev->prof_index) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Return zero instead here. Fixes: 028a2ae256916 ("ASoC: codecs: Add aw88261 amplifier driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230808125703.1611325-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/aw88261.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 82923b454dd4..6e2266b71386 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -652,6 +652,8 @@ static int aw88261_reg_update(struct aw88261 *aw88261, bool force) ret = aw88261_dev_fw_update(aw88261); if (ret) return ret; + } else { + ret = 0; } } -- cgit v1.2.3 From a932f45a1832d18fb64704636a958ef993a1d1da Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Tue, 8 Aug 2023 21:25:19 +0800 Subject: ASoC: pxa: address unused variable warning gcc with W=1 reports sound/soc/pxa/pxa-ssp.c:594:15: warning: variable 'acds' set but not used [-Wunused-but-set-variable] ^ This variable is not used so remove it. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308040619.BEismjFv-lkp@intel.com/ Signed-off-by: Yu Liao Link: https://lore.kernel.org/r/20230808132519.637452-1-liaoyu15@huawei.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 430dd446321e..d19769dde139 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (ret < 0) { const struct pxa_ssp_clock_mode *m; - int ssacd, acds; + int ssacd; for (m = pxa_ssp_clock_modes; m->rate; m++) { if (m->rate == rate) @@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (!m->rate) return -EINVAL; - acds = m->acds; - - /* The values in the table are for 16 bits */ - if (width == 32) - acds--; - ret = pxa_ssp_set_pll(priv, bclk); if (ret < 0) return ret; -- cgit v1.2.3 From 8e7b295da1ed051baedd068b7f785f5d959ef95d Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Mon, 7 Aug 2023 14:42:28 +0800 Subject: MAINTAINERS: Remove maintainer of HiSilicon RoCE Haoyue no longer maintains the Hisilicon RoCE driver. So remove him from MAINTAINERS. Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230807064228.4032536-1-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc..a65e2f53bffa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9364,7 +9364,6 @@ F: drivers/crypto/hisilicon/sgl.c F: include/linux/hisi_acc_qm.h HISILICON ROCE DRIVER -M: Haoyue Xu M: Junxian Huang L: linux-rdma@vger.kernel.org S: Maintained -- cgit v1.2.3 From 56675f8b9f9b15b024b8e3145fa289b004916ab7 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 20:04:09 +0200 Subject: io_uring/parisc: Adjust pgoff in io_uring mmap() for parisc The changes from commit 32832a407a71 ("io_uring: Fix io_uring mmap() by using architecture-provided get_unmapped_area()") to the parisc implementation of get_unmapped_area() broke glibc's locale-gen executable when running on parisc. This patch reverts those architecture-specific changes, and instead adjusts in io_uring_mmu_get_unmapped_area() the pgoff offset which is then given to parisc's get_unmapped_area() function. This is much cleaner than the previous approach, and we still will get a coherent addresss. This patch has no effect on other architectures (SHM_COLOUR is only defined on parisc), and the liburing testcase stil passes on parisc. Cc: stable@vger.kernel.org # 6.4 Signed-off-by: Helge Deller Reported-by: Christoph Biedl Fixes: 32832a407a71 ("io_uring: Fix io_uring mmap() by using architecture-provided get_unmapped_area()") Fixes: d808459b2e31 ("io_uring: Adjust mapping wrt architecture aliasing requirements") Link: https://lore.kernel.org/r/ZNEyGV0jyI8kOOfz@p100 Signed-off-by: Jens Axboe --- arch/parisc/kernel/sys_parisc.c | 15 +++++---------- io_uring/io_uring.c | 3 +++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index ca2d537e25b1..9915062d5243 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -27,17 +27,12 @@ #include /* - * Construct an artificial page offset for the mapping based on the virtual + * Construct an artificial page offset for the mapping based on the physical * address of the kernel file mapping variable. - * If filp is zero the calculated pgoff value aliases the memory of the given - * address. This is useful for io_uring where the mapping shall alias a kernel - * address and a userspace adress where both the kernel and the userspace - * access the same memory region. */ -#define GET_FILP_PGOFF(filp, addr) \ - ((filp ? (((unsigned long) filp->f_mapping) >> 8) \ - & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL) \ - + (addr >> PAGE_SHIFT)) +#define GET_FILP_PGOFF(filp) \ + (filp ? (((unsigned long) filp->f_mapping) >> 8) \ + & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL) static unsigned long shared_align_offset(unsigned long filp_pgoff, unsigned long pgoff) @@ -117,7 +112,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, do_color_align = 0; if (filp || (flags & MAP_SHARED)) do_color_align = 1; - filp_pgoff = GET_FILP_PGOFF(filp, addr); + filp_pgoff = GET_FILP_PGOFF(filp); if (flags & MAP_FIXED) { /* Even MAP_FIXED mappings must reside within TASK_SIZE */ diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index f4591b912ea8..93db3e4e7b68 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -3470,6 +3470,8 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp, * - use the kernel virtual address of the shared io_uring context * (instead of the userspace-provided address, which has to be 0UL * anyway). + * - use the same pgoff which the get_unmapped_area() uses to + * calculate the page colouring. * For architectures without such aliasing requirements, the * architecture will return any suitable mapping because addr is 0. */ @@ -3478,6 +3480,7 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp, pgoff = 0; /* has been translated to ptr above */ #ifdef SHM_COLOUR addr = (uintptr_t) ptr; + pgoff = addr >> PAGE_SHIFT; #else addr = 0UL; #endif -- cgit v1.2.3 From cc22522fd55e257c86d340ae9aedc122e705a435 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 26 Jul 2023 14:35:18 +0200 Subject: PCI: acpiphp: Use pci_assign_unassigned_bridge_resources() only for non-root bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 40613da52b13 ("PCI: acpiphp: Reassign resources on bridge if necessary") changed acpiphp hotplug to use pci_assign_unassigned_bridge_resources() which depends on bridge being available, however enable_slot() can be called without bridge associated: 1. Legitimate case of hotplug on root bus (widely used in virt world) 2. A (misbehaving) firmware, that sends ACPI Bus Check notifications to non existing root ports (Dell Inspiron 7352/0W6WV0), which end up at enable_slot(..., bridge = 0) where bus has no bridge assigned to it. acpihp doesn't know that it's a bridge, and bus specific 'PCI subsystem' can't augment ACPI context with bridge information since the PCI device to get this data from is/was not available. Issue is easy to reproduce with QEMU's 'pc' machine, which supports PCI hotplug on hostbridge slots. To reproduce, boot kernel at commit 40613da52b13 in VM started with following CLI (assuming guest root fs is installed on sda1 partition): # qemu-system-x86_64 -M pc -m 1G -enable-kvm -cpu host \ -monitor stdio -serial file:serial.log \ -kernel arch/x86/boot/bzImage \ -append "root=/dev/sda1 console=ttyS0" \ guest_disk.img Once guest OS is fully booted at qemu prompt: (qemu) device_add e1000 (check serial.log) it will cause NULL pointer dereference at: void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) { struct pci_bus *parent = bridge->subordinate; BUG: kernel NULL pointer dereference, address: 0000000000000018 ? pci_assign_unassigned_bridge_resources+0x1f/0x260 enable_slot+0x21f/0x3e0 acpiphp_hotplug_notify+0x13d/0x260 acpi_device_hotplug+0xbc/0x540 acpi_hotplug_work_fn+0x15/0x20 process_one_work+0x1f7/0x370 worker_thread+0x45/0x3b0 The issue was discovered on Dell Inspiron 7352/0W6WV0 laptop with following sequence: 1. Suspend to RAM 2. Wake up with the same backtrace being observed: 3. 2nd suspend to RAM attempt makes laptop freeze Fix it by using __pci_bus_assign_resources() instead of pci_assign_unassigned_bridge_resources() as we used to do, but only in case when bus doesn't have a bridge associated (to cover for the case of ACPI event on hostbridge or non existing root port). That lets us keep hotplug on root bus working like it used to and at the same time keeps resource reassignment usable on root ports (and other 1st level bridges) that was fixed by 40613da52b13. Fixes: 40613da52b13 ("PCI: acpiphp: Reassign resources on bridge if necessary") Link: https://lore.kernel.org/r/20230726123518.2361181-2-imammedo@redhat.com Reported-by: Woody Suwalski Tested-by: Woody Suwalski Tested-by: Michal KoutnĂœ Link: https://lore.kernel.org/r/11fc981c-af49-ce64-6b43-3e282728bd1a@gmail.com Signed-off-by: Igor Mammedov Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Acked-by: Michael S. Tsirkin --- drivers/pci/hotplug/acpiphp_glue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 328d1e416014..601129772b2d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -498,6 +498,7 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge) acpiphp_native_scan_bridge(dev); } } else { + LIST_HEAD(add_list); int max, pass; acpiphp_rescan_slot(slot); @@ -511,10 +512,15 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge) if (pass && dev->subordinate) { check_hotplug_bridge(slot, dev); pcibios_resource_survey_bus(dev->subordinate); + if (pci_is_root_bus(bus)) + __pci_bus_size_bridges(dev->subordinate, &add_list); } } } - pci_assign_unassigned_bridge_resources(bus->self); + if (pci_is_root_bus(bus)) + __pci_bus_assign_resources(bus, &add_list, NULL); + else + pci_assign_unassigned_bridge_resources(bus->self); } acpiphp_sanitize_bus(bus); -- cgit v1.2.3 From 7324f74d39531262b8e362f228b46512e6bee632 Mon Sep 17 00:00:00 2001 From: Jinghao Jia Date: Tue, 8 Aug 2023 14:23:53 -0400 Subject: x86/linkage: Fix typo of BUILD_VDSO in asm/linkage.h The BUILD_VDSO macro was incorrectly spelled as BULID_VDSO in asm/linkage.h. This causes the !defined(BULID_VDSO) directive to always evaluate to true. Correct the spelling to BUILD_VDSO. Fixes: bea75b33895f ("x86/Kconfig: Introduce function padding") Signed-off-by: Jinghao Jia Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Thomas Gleixner Acked-by: Randy Dunlap Cc: Link: https://lore.kernel.org/r/20230808182353.76218-1-jinghao@linux.ibm.com --- arch/x86/include/asm/linkage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h index 0953aa32a324..97a3de7892d3 100644 --- a/arch/x86/include/asm/linkage.h +++ b/arch/x86/include/asm/linkage.h @@ -21,7 +21,7 @@ #define FUNCTION_PADDING #endif -#if (CONFIG_FUNCTION_ALIGNMENT > 8) && !defined(__DISABLE_EXPORTS) && !defined(BULID_VDSO) +#if (CONFIG_FUNCTION_ALIGNMENT > 8) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO) # define __FUNC_ALIGN __ALIGN; FUNCTION_PADDING #else # define __FUNC_ALIGN __ALIGN -- cgit v1.2.3 From ebd0f7b08e032900e5327962f7da6bed6f37feb6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:46:58 +0100 Subject: ASoC: cs35l56: Avoid uninitialized variable in cs35l56_set_asp_slot_positions() Re-implement setting of ASP TDM slots so that only the common loop to build the register word is factored out. The original cs35l56_set_asp_slot_positions() had an apparent uninitialized variable if the passed register address was neither of the ASP slot registers. In fact this would never happen because the calling code passed valid registers. While it's trivial to initialize the variable or add a default case, actually the only common code was the loop at the end of the function, which simply manipulates some mask values and is identical for either register. Factoring out the regmap_write() didn't really gain anything. So instead re-implement the code to replace the original function with cs35l56_make_tdm_config_word() that only does the loop, and change the calling code to call regmap_write() directly. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 19b6b4fbe5de..be400208205a 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -358,22 +358,11 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f return 0; } -static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, - unsigned int reg, unsigned long mask) +static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask) { - unsigned int reg_val, channel_shift; + unsigned int channel_shift; int bit_num; - /* Init all slots to 63 */ - switch (reg) { - case CS35L56_ASP1_FRAME_CONTROL1: - reg_val = 0x3f3f3f3f; - break; - case CS35L56_ASP1_FRAME_CONTROL5: - reg_val = 0x3f3f3f; - break; - } - /* Enable consecutive TX1..TXn for each of the slots set in mask */ channel_shift = 0; for_each_set_bit(bit_num, &mask, 32) { @@ -382,7 +371,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, channel_shift += 8; } - regmap_write(cs35l56->base.regmap, reg, reg_val); + return reg_val; } static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, @@ -418,8 +407,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx if (rx_mask == 0) rx_mask = 0xf; // ASPTX1..TX4 in slots 0..3 - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask); - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask); + /* Default unused slots to 63 */ + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1, + cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask)); + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5, + cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask)); dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n", cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask); -- cgit v1.2.3 From 853734588dcb1bf4c41a17e4d9df231965e559db Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:46:59 +0100 Subject: ASoC: cs35l56: Don't rely on GPIOD_OUT_LOW to set RESET initially low The ACPI setting for a GPIO default state has higher priority than the flag passed to devm_gpiod_get_optional() so ACPI can override the GPIOD_OUT_LOW. Explicitly set the GPIO low when hard resetting. Although GPIOD_OUT_LOW can't be relied on this doesn't seem like a reason to stop passing it to devm_gpiod_get_optional(). So we still pass it to state our intent, but can deal with it having no effect. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index be400208205a..9560059c867b 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1069,6 +1069,8 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n"); if (cs35l56->base.reset_gpio) { + /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); } -- cgit v1.2.3 From f5eb9503e80e70c22e3d3f73a5d3c149c132407f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:47:00 +0100 Subject: ASoC: cs35l56: Wait for control port ready during system-resume The CS35L56 could be hard-reset during a system suspend-resume cycle, either by the codec driver, in cs35l56_system_resume_early(), or by ACPI. After a hard reset the driver must wait for the control port to be ready (datasheet tIRS time) before attempting to access the CS35L56. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 9560059c867b..094bcbd0a174 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -952,6 +952,12 @@ int cs35l56_system_resume(struct device *dev) dev_dbg(dev, "system_resume\n"); + /* + * We might have done a hard reset or the CS35L56 was power-cycled + * so wait for control port to be ready. + */ + cs35l56_wait_control_port_ready(); + /* Undo pm_runtime_force_suspend() before re-enabling the irq */ ret = pm_runtime_force_resume(dev); if (cs35l56->base.irq) -- cgit v1.2.3 From d0a3a6ad0d3b24578f1b3832ad1d7fbdb20f7a20 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 8 Aug 2023 17:47:01 +0100 Subject: ASoC: wm_adsp: Expose the DSP power down actions as wm_adsp_power_down() To support self-booting DSPs that operate outside of a conventional DAPM event life cycle expose a companion function to wm_adsp_power_up() so that the correct state of the DSP firmware and controls can be recorded. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 8 +++++++- sound/soc/codecs/wm_adsp.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 5a89abfe8784..13f500fa9a5f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1025,6 +1025,12 @@ int wm_adsp_power_up(struct wm_adsp *dsp) } EXPORT_SYMBOL_GPL(wm_adsp_power_up); +void wm_adsp_power_down(struct wm_adsp *dsp) +{ + cs_dsp_power_down(&dsp->cs_dsp); +} +EXPORT_SYMBOL_GPL(wm_adsp_power_down); + static void wm_adsp_boot_work(struct work_struct *work) { struct wm_adsp *dsp = container_of(work, @@ -1046,7 +1052,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, queue_work(system_unbound_wq, &dsp->boot_work); break; case SND_SOC_DAPM_PRE_PMD: - cs_dsp_power_down(&dsp->cs_dsp); + wm_adsp_power_down(dsp); break; default: break; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 769904d34a87..3044f964ac14 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -92,6 +92,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); int wm_adsp_power_up(struct wm_adsp *dsp); +void wm_adsp_power_down(struct wm_adsp *dsp); irqreturn_t wm_adsp2_bus_error(int irq, void *data); irqreturn_t wm_halo_bus_error(int irq, void *data); -- cgit v1.2.3 From e24ef967c735bf7272099610e422f964c0a4258b Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 8 Aug 2023 17:47:02 +0100 Subject: ASoC: cs35l56: Call wm_adsp_power_down() before reloading firmware When cs35l56_system_resume() needs to reload firmware it should call wm_adsp_power_down() to put cs_dsp into a powered-down state before cs35l56_secure_patch() or cs35l56_patch() calls wm_adsp_power_up(). Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 094bcbd0a174..80e7fddae926 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -976,6 +976,7 @@ int cs35l56_system_resume(struct device *dev) return ret; cs35l56->base.fw_patched = false; + wm_adsp_power_down(&cs35l56->dsp); queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); /* -- cgit v1.2.3 From fa40ea27ede397cb19b8cb264f136db9c43c6f7e Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 4 Aug 2023 08:00:07 +0300 Subject: MAINTAINERS: update Claudiu Beznea's email address Update MAINTAINERS entries with a valid email address as the Microchip one is no longer valid. Acked-by: Conor Dooley Acked-by: Nicolas Ferre Signed-off-by: Claudiu Beznea Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230804050007.235799-1-claudiu.beznea@tuxon.dev Signed-off-by: Jakub Kicinski --- MAINTAINERS | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 92d23da63638..fa3e8ff79bf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2339,7 +2339,7 @@ F: drivers/phy/mediatek/ ARM/MICROCHIP (ARM64) SoC support M: Conor Dooley M: Nicolas Ferre -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported T: git https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git @@ -2348,7 +2348,7 @@ F: arch/arm64/boot/dts/microchip/ ARM/Microchip (AT91) SoC support M: Nicolas Ferre M: Alexandre Belloni -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported W: http://www.linux4sam.org @@ -3250,7 +3250,7 @@ F: include/uapi/linux/atm* ATMEL MACB ETHERNET DRIVER M: Nicolas Ferre -M: Claudiu Beznea +M: Claudiu Beznea S: Supported F: drivers/net/ethernet/cadence/ @@ -13785,7 +13785,7 @@ F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml F: drivers/spi/spi-at91-usart.c MICROCHIP AUDIO ASOC DRIVERS -M: Claudiu Beznea +M: Claudiu Beznea L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/sound/atmel* @@ -13808,7 +13808,7 @@ S: Maintained F: drivers/crypto/atmel-ecc.* MICROCHIP EIC DRIVER -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/interrupt-controller/microchip,sama7g5-eic.yaml @@ -13881,7 +13881,7 @@ F: drivers/video/fbdev/atmel_lcdfb.c F: include/video/atmel_lcdc.h MICROCHIP MCP16502 PMIC DRIVER -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt @@ -13908,7 +13908,7 @@ F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: drivers/mtd/nand/raw/atmel/* MICROCHIP OTPC DRIVER -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml @@ -13947,7 +13947,7 @@ F: Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml F: drivers/fpga/microchip-spi.c MICROCHIP PWM DRIVER -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-pwm@vger.kernel.org S: Supported @@ -13963,7 +13963,7 @@ F: drivers/iio/adc/at91-sama5d2_adc.c F: include/dt-bindings/iio/adc/at91-sama5d2_adc.h MICROCHIP SAMA5D2-COMPATIBLE SHUTDOWN CONTROLLER -M: Claudiu Beznea +M: Claudiu Beznea S: Supported F: Documentation/devicetree/bindings/power/reset/atmel,sama5d2-shdwc.yaml F: drivers/power/reset/at91-sama5d2_shdwc.c @@ -13980,7 +13980,7 @@ S: Supported F: drivers/spi/spi-atmel.* MICROCHIP SSC DRIVER -M: Claudiu Beznea +M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -14009,7 +14009,7 @@ F: drivers/usb/gadget/udc/atmel_usba_udc.* MICROCHIP WILC1000 WIFI DRIVER M: Ajay Singh -M: Claudiu Beznea +M: Claudiu Beznea L: linux-wireless@vger.kernel.org S: Supported F: drivers/net/wireless/microchip/wilc1000/ -- cgit v1.2.3 From d74f714896fd6268882789ba28e52c9145951403 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 8 Aug 2023 11:03:28 -0600 Subject: block: get rid of unused plug->nowait flag This was introduced to add a plug based way of signaling nowait issues, but we have since moved on from that. Kill the old dead code, nobody is setting it anymore. Reviewed-by: Chaitanya Kulkarni Reviewed-by: Bart Van Assche Signed-off-by: Jens Axboe --- block/blk-core.c | 6 ------ include/linux/blkdev.h | 1 - 2 files changed, 7 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 90de50082146..9866468c72a2 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -722,14 +722,9 @@ void submit_bio_noacct(struct bio *bio) struct block_device *bdev = bio->bi_bdev; struct request_queue *q = bdev_get_queue(bdev); blk_status_t status = BLK_STS_IOERR; - struct blk_plug *plug; might_sleep(); - plug = blk_mq_plug(bio); - if (plug && plug->nowait) - bio->bi_opf |= REQ_NOWAIT; - /* * For a REQ_NOWAIT based request, return -EOPNOTSUPP * if queue does not support NOWAIT. @@ -1059,7 +1054,6 @@ void blk_start_plug_nr_ios(struct blk_plug *plug, unsigned short nr_ios) plug->rq_count = 0; plug->multiple_queues = false; plug->has_elevator = false; - plug->nowait = false; INIT_LIST_HEAD(&plug->cb_list); /* diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ed44a997f629..87d94be7825a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -969,7 +969,6 @@ struct blk_plug { bool multiple_queues; bool has_elevator; - bool nowait; struct list_head cb_list; /* md requires an unplug callback */ }; -- cgit v1.2.3 From 6514f81e1bd55cbe419a5001a4ce910acc276211 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 2 Aug 2023 18:26:06 -0700 Subject: riscv: Fix CPU feature detection with SMP disabled commit 914d6f44fc50 ("RISC-V: only iterate over possible CPUs in ISA string parser") changed riscv_fill_hwcap() from iterating over CPU DT nodes to iterating over logical CPU IDs. Since this function runs long before cpu_dev_init() creates CPU devices, it hits the fallback path in of_cpu_device_node_get(), which itself iterates over the DT nodes, searching for a node with the requested CPU ID. (Incidentally, this makes riscv_fill_hwcap() now take quadratic time.) riscv_fill_hwcap() passes a logical CPU ID to of_cpu_device_node_get(), which uses the arch_match_cpu_phys_id() hook to translate the logical ID to a physical ID as found in the DT. arch_match_cpu_phys_id() has a generic weak definition, and RISC-V provides a strong definition using cpuid_to_hartid_map(). However, the RISC-V specific implementation is located in arch/riscv/kernel/smp.c, and that file is only compiled when SMP is enabled. As a result, when SMP is disabled, the generic definition is used, and riscv_isa gets initialized based on the ISA string of hart 0, not the boot hart. On FU740, this means has_fpu() returns false, and userspace crashes when trying to use floating-point instructions. Fix this by moving arch_match_cpu_phys_id() to a file which is always compiled. Fixes: 70114560b285 ("RISC-V: Add RISC-V specific arch_match_cpu_phys_id") Fixes: 914d6f44fc50 ("RISC-V: only iterate over possible CPUs in ISA string parser") Reported-by: Palmer Dabbelt Signed-off-by: Samuel Holland Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230803012608.3540081-1-samuel.holland@sifive.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/cpu.c | 5 +++++ arch/riscv/kernel/smp.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index a2fc952318e9..35b854cf078e 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -17,6 +17,11 @@ #include #include +bool arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return phys_id == cpuid_to_hartid_map(cpu); +} + /* * Returns the hart ID of the given device tree node, or -ENODEV if the node * isn't an enabled and valid RISC-V hart node. diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 85bbce0f758c..40420afbb1a0 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -61,11 +61,6 @@ int riscv_hartid_to_cpuid(unsigned long hartid) return -ENOENT; } -bool arch_match_cpu_phys_id(int cpu, u64 phys_id) -{ - return phys_id == cpuid_to_hartid_map(cpu); -} - static void ipi_stop(void) { set_cpu_online(smp_processor_id(), false); -- cgit v1.2.3 From 4eb2eb1b4c0eb07793c240744843498564a67b83 Mon Sep 17 00:00:00 2001 From: Andrea Parri Date: Thu, 3 Aug 2023 06:27:38 +0200 Subject: riscv,mmio: Fix readX()-to-delay() ordering Section 2.1 of the Platform Specification [1] states: Unless otherwise specified by a given I/O device, I/O devices are on ordering channel 0 (i.e., they are point-to-point strongly ordered). which is not sufficient to guarantee that a readX() by a hart completes before a subsequent delay() on the same hart (cf. memory-barriers.txt, "Kernel I/O barrier effects"). Set the I(nput) bit in __io_ar() to restore the ordering, align inline comments. [1] https://github.com/riscv/riscv-platform-specs Signed-off-by: Andrea Parri Link: https://lore.kernel.org/r/20230803042738.5937-1-parri.andrea@gmail.com Fixes: fab957c11efe ("RISC-V: Atomic and Locking Code") Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/mmio.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/riscv/include/asm/mmio.h b/arch/riscv/include/asm/mmio.h index aff6c33ab0c0..4c58ee7f95ec 100644 --- a/arch/riscv/include/asm/mmio.h +++ b/arch/riscv/include/asm/mmio.h @@ -101,9 +101,9 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) * Relaxed I/O memory access primitives. These follow the Device memory * ordering rules but do not guarantee any ordering relative to Normal memory * accesses. These are defined to order the indicated access (either a read or - * write) with all other I/O memory accesses. Since the platform specification - * defines that all I/O regions are strongly ordered on channel 2, no explicit - * fences are required to enforce this ordering. + * write) with all other I/O memory accesses to the same peripheral. Since the + * platform specification defines that all I/O regions are strongly ordered on + * channel 0, no explicit fences are required to enforce this ordering. */ /* FIXME: These are now the same as asm-generic */ #define __io_rbr() do {} while (0) @@ -125,14 +125,14 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) #endif /* - * I/O memory access primitives. Reads are ordered relative to any - * following Normal memory access. Writes are ordered relative to any prior - * Normal memory access. The memory barriers here are necessary as RISC-V + * I/O memory access primitives. Reads are ordered relative to any following + * Normal memory read and delay() loop. Writes are ordered relative to any + * prior Normal memory write. The memory barriers here are necessary as RISC-V * doesn't define any ordering between the memory space and the I/O space. */ #define __io_br() do {} while (0) -#define __io_ar(v) __asm__ __volatile__ ("fence i,r" : : : "memory") -#define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory") +#define __io_ar(v) ({ __asm__ __volatile__ ("fence i,ir" : : : "memory"); }) +#define __io_bw() ({ __asm__ __volatile__ ("fence w,o" : : : "memory"); }) #define __io_aw() mmiowb_set_pending() #define readb(c) ({ u8 __v; __io_br(); __v = readb_cpu(c); __io_ar(__v); __v; }) -- cgit v1.2.3 From d2402048bc8a206a56fde4bc41dd01336c7b5a21 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Tue, 8 Aug 2023 09:35:00 -0700 Subject: riscv: mm: fix 2 instances of -Wmissing-variable-declarations I'm looking to enable -Wmissing-variable-declarations behind W=1. 0day bot spotted the following instance in ARCH=riscv builds: arch/riscv/mm/init.c:276:7: warning: no previous extern declaration for non-static variable 'trampoline_pg_dir' [-Wmissing-variable-declarations] 276 | pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; | ^ arch/riscv/mm/init.c:276:1: note: declare 'static' if the variable is not intended to be used outside of this translation unit 276 | pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; | ^ arch/riscv/mm/init.c:279:7: warning: no previous extern declaration for non-static variable 'early_pg_dir' [-Wmissing-variable-declarations] 279 | pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); | ^ arch/riscv/mm/init.c:279:1: note: declare 'static' if the variable is not intended to be used outside of this translation unit 279 | pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); | ^ These symbols are referenced by more than one translation unit, so make sure they're both declared and include the correct header for their declarations. Finally, sort the list of includes to help keep them tidy. Reported-by: kernel test robot Closes: https://lore.kernel.org/llvm/202308081000.tTL1ElTr-lkp@intel.com/ Signed-off-by: Nick Desaulniers Link: https://lore.kernel.org/r/20230808-riscv_static-v2-1-2a1e2d2c7a4f@google.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/pgtable.h | 2 ++ arch/riscv/mm/init.c | 9 +++++---- arch/riscv/mm/kasan_init.c | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 75970ee2bda2..b5680c940c1e 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -188,6 +188,8 @@ extern struct pt_alloc_ops pt_ops __initdata; #define PAGE_KERNEL_IO __pgprot(_PAGE_IOREMAP) extern pgd_t swapper_pg_dir[]; +extern pgd_t trampoline_pg_dir[]; +extern pgd_t early_pg_dir[]; #ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline int pmd_present(pmd_t pmd) diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index ad845c3aa9b2..e4c35ac2357f 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -26,12 +26,13 @@ #include #include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include #include "../kernel/head.h" diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c index 8fc0efcf905c..a01bc15dce24 100644 --- a/arch/riscv/mm/kasan_init.c +++ b/arch/riscv/mm/kasan_init.c @@ -22,7 +22,6 @@ * region is not and then we have to go down to the PUD level. */ -extern pgd_t early_pg_dir[PTRS_PER_PGD]; pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss; p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss; pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss; -- cgit v1.2.3 From b6f79e826fbd26e91e2fb28070484634cacdeb26 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 7 Aug 2023 10:12:25 +0200 Subject: net/unix: use consistent error code in SO_PEERPIDFD Change the new (unreleased) SO_PEERPIDFD sockopt to return ENODATA rather than ESRCH if a socket type does not support remote peer-PID queries. Currently, SO_PEERPIDFD returns ESRCH when the socket in question is not an AF_UNIX socket. This is quite unexpected, given that one would assume ESRCH means the peer process already exited and thus cannot be found. However, in that case the sockopt actually returns EINVAL (via pidfd_prepare()). This is rather inconsistent with other syscalls, which usually return ESRCH if a given PID refers to a non-existant process. This changes SO_PEERPIDFD to return ENODATA instead. This is also what SO_PEERGROUPS returns, and thus keeps a consistent behavior across sockopts. Note that this code is returned in 2 cases: First, if the socket type is not AF_UNIX, and secondly if the socket was not yet connected. In both cases ENODATA seems suitable. Signed-off-by: David Rheinsberg Reviewed-by: Christian Brauner Acked-by: Luca Boccassi Fixes: 7b26952a91cf ("net: core: add getsockopt SO_PEERPIDFD") Link: https://lore.kernel.org/r/20230807081225.816199-1-david@readahead.eu Signed-off-by: Jakub Kicinski --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index 6d4f28efe29a..732fc37a4771 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1778,7 +1778,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, spin_unlock(&sk->sk_peer_lock); if (!peer_pid) - return -ESRCH; + return -ENODATA; pidfd = pidfd_prepare(peer_pid, 0, &pidfd_file); put_pid(peer_pid); -- cgit v1.2.3 From 15159ec0c831b565820c2de05114ea1b4cf07681 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 7 Aug 2023 19:34:49 +0800 Subject: net: hns3: restore user pause configure when disable autoneg Restore the mac pause state to user configuration when autoneg is disabled Signed-off-by: Jian Shen Signed-off-by: Peiyang Wang Signed-off-by: Jijie Shao Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230807113452.474224-2-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 5 ++++- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index bf675c15fbb9..5594b8dd1e1d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -10915,9 +10915,12 @@ int hclge_cfg_flowctrl(struct hclge_dev *hdev) u32 rx_pause, tx_pause; u8 flowctl; - if (!phydev->link || !phydev->autoneg) + if (!phydev->link) return 0; + if (!phydev->autoneg) + return hclge_mac_pause_setup_hw(hdev); + local_advertising = linkmode_adv_to_lcl_adv_t(phydev->advertising); if (phydev->pause) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index de509e5751a7..c58c31221762 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1553,7 +1553,7 @@ static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc) return 0; } -static int hclge_mac_pause_setup_hw(struct hclge_dev *hdev) +int hclge_mac_pause_setup_hw(struct hclge_dev *hdev) { bool tx_en, rx_en; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 45dcfef3f90c..53eec6df5194 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -245,6 +245,7 @@ int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, u8 pfc_bitmap); int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx); int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr); +int hclge_mac_pause_setup_hw(struct hclge_dev *hdev); void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats); void hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats); int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate); -- cgit v1.2.3 From 08469dacfad25428b66549716811807203744f4f Mon Sep 17 00:00:00 2001 From: Jie Wang Date: Mon, 7 Aug 2023 19:34:50 +0800 Subject: net: hns3: refactor hclge_mac_link_status_wait for interface reuse Some nic configurations could only be performed after link is down. So this patch refactor this API for reuse. Signed-off-by: Jie Wang Signed-off-by: Jijie Shao Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230807113452.474224-3-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 5594b8dd1e1d..b440e42e1d9c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -72,6 +72,8 @@ static void hclge_restore_hw_table(struct hclge_dev *hdev); static void hclge_sync_promisc_mode(struct hclge_dev *hdev); static void hclge_sync_fd_table(struct hclge_dev *hdev); static void hclge_update_fec_stats(struct hclge_dev *hdev); +static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret, + int wait_cnt); static struct hnae3_ae_algo ae_algo; @@ -7647,10 +7649,9 @@ static void hclge_phy_link_status_wait(struct hclge_dev *hdev, } while (++i < HCLGE_PHY_LINK_STATUS_NUM); } -static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret) +static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret, + int wait_cnt) { -#define HCLGE_MAC_LINK_STATUS_NUM 100 - int link_status; int i = 0; int ret; @@ -7663,13 +7664,15 @@ static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret) return 0; msleep(HCLGE_LINK_STATUS_MS); - } while (++i < HCLGE_MAC_LINK_STATUS_NUM); + } while (++i < wait_cnt); return -EBUSY; } static int hclge_mac_phy_link_status_wait(struct hclge_dev *hdev, bool en, bool is_phy) { +#define HCLGE_MAC_LINK_STATUS_NUM 100 + int link_ret; link_ret = en ? HCLGE_LINK_STATUS_UP : HCLGE_LINK_STATUS_DOWN; @@ -7677,7 +7680,8 @@ static int hclge_mac_phy_link_status_wait(struct hclge_dev *hdev, bool en, if (is_phy) hclge_phy_link_status_wait(hdev, link_ret); - return hclge_mac_link_status_wait(hdev, link_ret); + return hclge_mac_link_status_wait(hdev, link_ret, + HCLGE_MAC_LINK_STATUS_NUM); } static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en) -- cgit v1.2.3 From 6265e242f7b95f2c1195b42ec912b84ad161470e Mon Sep 17 00:00:00 2001 From: Jie Wang Date: Mon, 7 Aug 2023 19:34:51 +0800 Subject: net: hns3: add wait until mac link down In some configure flow of hns3 driver, for example, change mtu, it will disable MAC through firmware before configuration. But firmware disables MAC asynchronously. The rx traffic may be not stopped in this case. So fixes it by waiting until mac link is down. Fixes: a9775bb64aa7 ("net: hns3: fix set and get link ksettings issue") Signed-off-by: Jie Wang Signed-off-by: Jijie Shao Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230807113452.474224-4-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index b440e42e1d9c..a940e35aef29 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7560,6 +7560,8 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable) static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { +#define HCLGE_LINK_STATUS_WAIT_CNT 3 + struct hclge_desc desc; struct hclge_config_mac_mode_cmd *req = (struct hclge_config_mac_mode_cmd *)desc.data; @@ -7584,9 +7586,15 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en); ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret) + if (ret) { dev_err(&hdev->pdev->dev, "mac enable fail, ret =%d.\n", ret); + return; + } + + if (!enable) + hclge_mac_link_status_wait(hdev, HCLGE_LINK_STATUS_DOWN, + HCLGE_LINK_STATUS_WAIT_CNT); } static int hclge_config_switch_param(struct hclge_dev *hdev, int vfid, -- cgit v1.2.3 From ac6257a3ae5db5193b1f19c268e4f72d274ddb88 Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Mon, 7 Aug 2023 19:34:52 +0800 Subject: net: hns3: fix deadlock issue when externel_lb and reset are executed together When externel_lb and reset are executed together, a deadlock may occur: [ 3147.217009] INFO: task kworker/u321:0:7 blocked for more than 120 seconds. [ 3147.230483] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 3147.238999] task:kworker/u321:0 state:D stack: 0 pid: 7 ppid: 2 flags:0x00000008 [ 3147.248045] Workqueue: hclge hclge_service_task [hclge] [ 3147.253957] Call trace: [ 3147.257093] __switch_to+0x7c/0xbc [ 3147.261183] __schedule+0x338/0x6f0 [ 3147.265357] schedule+0x50/0xe0 [ 3147.269185] schedule_preempt_disabled+0x18/0x24 [ 3147.274488] __mutex_lock.constprop.0+0x1d4/0x5dc [ 3147.279880] __mutex_lock_slowpath+0x1c/0x30 [ 3147.284839] mutex_lock+0x50/0x60 [ 3147.288841] rtnl_lock+0x20/0x2c [ 3147.292759] hclge_reset_prepare+0x68/0x90 [hclge] [ 3147.298239] hclge_reset_subtask+0x88/0xe0 [hclge] [ 3147.303718] hclge_reset_service_task+0x84/0x120 [hclge] [ 3147.309718] hclge_service_task+0x2c/0x70 [hclge] [ 3147.315109] process_one_work+0x1d0/0x490 [ 3147.319805] worker_thread+0x158/0x3d0 [ 3147.324240] kthread+0x108/0x13c [ 3147.328154] ret_from_fork+0x10/0x18 In externel_lb process, the hns3 driver call napi_disable() first, then the reset happen, then the restore process of the externel_lb will fail, and will not call napi_enable(). When doing externel_lb again, napi_disable() will be double call, cause a deadlock of rtnl_lock(). This patch use the HNS3_NIC_STATE_DOWN state to protect the calling of napi_disable() and napi_enable() in externel_lb process, just as the usage in ndo_stop() and ndo_start(). Fixes: 04b6ba143521 ("net: hns3: add support for external loopback test") Signed-off-by: Yonglong Liu Signed-off-by: Jijie Shao Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230807113452.474224-5-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 9f6890059666..b7b51e56b030 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -5854,6 +5854,9 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running) if (!if_running) return; + if (test_and_set_bit(HNS3_NIC_STATE_DOWN, &priv->state)) + return; + netif_carrier_off(ndev); netif_tx_disable(ndev); @@ -5882,7 +5885,16 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running) if (!if_running) return; - hns3_nic_reset_all_ring(priv->ae_handle); + if (hns3_nic_resetting(ndev)) + return; + + if (!test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) + return; + + if (hns3_nic_reset_all_ring(priv->ae_handle)) + return; + + clear_bit(HNS3_NIC_STATE_DOWN, &priv->state); for (i = 0; i < priv->vector_num; i++) hns3_vector_enable(&priv->tqp_vector[i]); -- cgit v1.2.3 From 06b412589eef780b792e73df131d35dc43cc4a49 Mon Sep 17 00:00:00 2001 From: Muhammad Husaini Zulkifli Date: Mon, 7 Aug 2023 13:51:29 -0700 Subject: igc: Add lock to safeguard global Qbv variables Access to shared variables through hrtimer requires locking in order to protect the variables because actions to write into these variables (oper_gate_closed, admin_gate_closed, and qbv_transition) might potentially occur simultaneously. This patch provides a locking mechanisms to avoid such scenarios. Fixes: 175c241288c0 ("igc: Fix TX Hang issue when QBV Gate is closed") Suggested-by: Leon Romanovsky Signed-off-by: Muhammad Husaini Zulkifli Tested-by: Naama Meir Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20230807205129.3129346-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/igc/igc.h | 4 ++++ drivers/net/ethernet/intel/igc/igc_main.c | 34 +++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 9db384f66a8e..38901d2a4680 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -195,6 +195,10 @@ struct igc_adapter { u32 qbv_config_change_errors; bool qbv_transition; unsigned int qbv_count; + /* Access to oper_gate_closed, admin_gate_closed and qbv_transition + * are protected by the qbv_tx_lock. + */ + spinlock_t qbv_tx_lock; /* OS defined structs */ struct pci_dev *pdev; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index bdeb36790d77..6f557e843e49 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4801,6 +4801,7 @@ static int igc_sw_init(struct igc_adapter *adapter) adapter->nfc_rule_count = 0; spin_lock_init(&adapter->stats64_lock); + spin_lock_init(&adapter->qbv_tx_lock); /* Assume MSI-X interrupts, will be checked during IRQ allocation */ adapter->flags |= IGC_FLAG_HAS_MSIX; @@ -6119,15 +6120,15 @@ static int igc_tsn_enable_launchtime(struct igc_adapter *adapter, return igc_tsn_offload_apply(adapter); } -static int igc_tsn_clear_schedule(struct igc_adapter *adapter) +static int igc_qbv_clear_schedule(struct igc_adapter *adapter) { + unsigned long flags; int i; adapter->base_time = 0; adapter->cycle_time = NSEC_PER_SEC; adapter->taprio_offload_enable = false; adapter->qbv_config_change_errors = 0; - adapter->qbv_transition = false; adapter->qbv_count = 0; for (i = 0; i < adapter->num_tx_queues; i++) { @@ -6136,10 +6137,28 @@ static int igc_tsn_clear_schedule(struct igc_adapter *adapter) ring->start_time = 0; ring->end_time = NSEC_PER_SEC; ring->max_sdu = 0; + } + + spin_lock_irqsave(&adapter->qbv_tx_lock, flags); + + adapter->qbv_transition = false; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *ring = adapter->tx_ring[i]; + ring->oper_gate_closed = false; ring->admin_gate_closed = false; } + spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags); + + return 0; +} + +static int igc_tsn_clear_schedule(struct igc_adapter *adapter) +{ + igc_qbv_clear_schedule(adapter); + return 0; } @@ -6150,6 +6169,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, struct igc_hw *hw = &adapter->hw; u32 start_time = 0, end_time = 0; struct timespec64 now; + unsigned long flags; size_t n; int i; @@ -6217,6 +6237,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, start_time += e->interval; } + spin_lock_irqsave(&adapter->qbv_tx_lock, flags); + /* Check whether a queue gets configured. * If not, set the start and end time to be end time. */ @@ -6241,6 +6263,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, } } + spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags); + for (i = 0; i < adapter->num_tx_queues; i++) { struct igc_ring *ring = adapter->tx_ring[i]; struct net_device *dev = adapter->netdev; @@ -6619,8 +6643,11 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer) { struct igc_adapter *adapter = container_of(timer, struct igc_adapter, hrtimer); + unsigned long flags; unsigned int i; + spin_lock_irqsave(&adapter->qbv_tx_lock, flags); + adapter->qbv_transition = true; for (i = 0; i < adapter->num_tx_queues; i++) { struct igc_ring *tx_ring = adapter->tx_ring[i]; @@ -6633,6 +6660,9 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer) } } adapter->qbv_transition = false; + + spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags); + return HRTIMER_NORESTART; } -- cgit v1.2.3 From 0fb1d8eb234b6979d4981d2d385780dd7d8d9771 Mon Sep 17 00:00:00 2001 From: Piotr Gardocki Date: Mon, 7 Aug 2023 13:50:11 -0700 Subject: iavf: fix potential races for FDIR filters Add fdir_fltr_lock locking in unprotected places. The change in iavf_fdir_is_dup_fltr adds a spinlock around a loop which iterates over all filters and looks for a duplicate. The filter can be removed from list and freed from memory at the same time it's being compared. All other places where filters are deleted are already protected with spinlock. The remaining changes protect adapter->fdir_active_fltr variable so now all its uses are under a spinlock. Fixes: 527691bf0682 ("iavf: Support IPv4 Flow Director filters") Signed-off-by: Piotr Gardocki Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230807205011.3129224-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 5 ++++- drivers/net/ethernet/intel/iavf/iavf_fdir.c | 11 ++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index 2f47cfa7f06e..460ca561819a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -1401,14 +1401,15 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx if (fsp->flow_type & FLOW_MAC_EXT) return -EINVAL; + spin_lock_bh(&adapter->fdir_fltr_lock); if (adapter->fdir_active_fltr >= IAVF_MAX_FDIR_FILTERS) { + spin_unlock_bh(&adapter->fdir_fltr_lock); dev_err(&adapter->pdev->dev, "Unable to add Flow Director filter because VF reached the limit of max allowed filters (%u)\n", IAVF_MAX_FDIR_FILTERS); return -ENOSPC; } - spin_lock_bh(&adapter->fdir_fltr_lock); if (iavf_find_fdir_fltr_by_loc(adapter, fsp->location)) { dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, it already exists\n"); spin_unlock_bh(&adapter->fdir_fltr_lock); @@ -1781,7 +1782,9 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, case ETHTOOL_GRXCLSRLCNT: if (!FDIR_FLTR_SUPPORT(adapter)) break; + spin_lock_bh(&adapter->fdir_fltr_lock); cmd->rule_cnt = adapter->fdir_active_fltr; + spin_unlock_bh(&adapter->fdir_fltr_lock); cmd->data = IAVF_MAX_FDIR_FILTERS; ret = 0; break; diff --git a/drivers/net/ethernet/intel/iavf/iavf_fdir.c b/drivers/net/ethernet/intel/iavf/iavf_fdir.c index 6146203efd84..505e82ebafe4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_fdir.c +++ b/drivers/net/ethernet/intel/iavf/iavf_fdir.c @@ -722,7 +722,9 @@ void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *f bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) { struct iavf_fdir_fltr *tmp; + bool ret = false; + spin_lock_bh(&adapter->fdir_fltr_lock); list_for_each_entry(tmp, &adapter->fdir_list_head, list) { if (tmp->flow_type != fltr->flow_type) continue; @@ -732,11 +734,14 @@ bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr * !memcmp(&tmp->ip_data, &fltr->ip_data, sizeof(fltr->ip_data)) && !memcmp(&tmp->ext_data, &fltr->ext_data, - sizeof(fltr->ext_data))) - return true; + sizeof(fltr->ext_data))) { + ret = true; + break; + } } + spin_unlock_bh(&adapter->fdir_fltr_lock); - return false; + return ret; } /** -- cgit v1.2.3 From 1a8c251cff2052b60009a070173308322e9600d3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 3 Aug 2023 16:58:56 +0300 Subject: PCI: move OF status = "disabled" detection to dev->match_driver The blamed commit has broken probing on arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi when &enetc_port0 (PCI function 0) has status = "disabled". Background: pci_scan_slot() has logic to say that if the function 0 of a device is absent, the entire device is absent and we can skip the other functions entirely. Traditionally, this has meant that pci_bus_read_dev_vendor_id() returns an error code for that function. However, since the blamed commit, there is an extra confounding condition: function 0 of the device exists and has a valid vendor id, but it is disabled in the device tree. In that case, pci_scan_slot() would incorrectly skip the entire device instead of just that function. In the case of NXP LS1028A, status = "disabled" does not mean that the PCI function's config space is not available for reading. It is, but the Ethernet port is just not functionally useful with a particular SerDes protocol configuration (0x9999) due to pinmuxing constraints of the Soc. So, pci_scan_slot() skips all other functions on the ENETC ECAM (enetc_port1, enetc_port2, enetc_mdio_pf3 etc) when just enetc_port0 had to not be probed. There is an additional regression introduced by the change, caused by its fundamental premise. The enetc driver needs to run code for all PCI functions, regardless of whether they're enabled or not in the device tree. That is no longer possible if the driver's probe function is no longer called. But Rob recommends that we move the of_device_is_available() detection to dev->match_driver, and this makes the PCI fixups still run on all functions, while just probing drivers for those functions that are enabled. So, a separate change in the enetc driver will have to move the workarounds to a PCI fixup. Fixes: 6fffbc7ae137 ("PCI: Honor firmware's device disabled status") Link: https://lore.kernel.org/netdev/CAL_JsqLsVYiPLx2kcHkDQ4t=hQVCR7NHziDwi9cCFUFhx48Qow@mail.gmail.com/ Suggested-by: Rob Herring Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/pci/bus.c | 4 +++- drivers/pci/of.c | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 5bc81cc0a2de..46b252bbe500 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -332,6 +333,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { } */ void pci_bus_add_device(struct pci_dev *dev) { + struct device_node *dn = dev->dev.of_node; int retval; /* @@ -344,7 +346,7 @@ void pci_bus_add_device(struct pci_dev *dev) pci_proc_attach_device(dev); pci_bridge_d3_update(dev); - dev->match_driver = true; + dev->match_driver = !dn || of_device_is_available(dn); retval = device_attach(&dev->dev); if (retval < 0 && retval != -EPROBE_DEFER) pci_warn(dev, "device attach failed (%d)\n", retval); diff --git a/drivers/pci/of.c b/drivers/pci/of.c index e51219f9f523..3c158b17dcb5 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -34,11 +34,6 @@ int pci_set_of_node(struct pci_dev *dev) if (!node) return 0; - if (!of_device_is_available(node)) { - of_node_put(node); - return -ENODEV; - } - device_set_node(&dev->dev, of_fwnode_handle(node)); return 0; } -- cgit v1.2.3 From f0168042a21292d20007d24ab2e4fc32f79ebf11 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 3 Aug 2023 16:58:57 +0300 Subject: net: enetc: reimplement RFS/RSS memory clearing as PCI quirk The workaround implemented in commit 3222b5b613db ("net: enetc: initialize RFS/RSS memories for unused ports too") is no longer effective after commit 6fffbc7ae137 ("PCI: Honor firmware's device disabled status"). Thus, it has introduced a regression and we see AER errors being reported again: $ ip link set sw2p0 up && dhclient -i sw2p0 && ip addr show sw2p0 fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode fsl_enetc 0000:00:00.2 eno2: Link is Up - 2.5Gbps/Full - flow control rx/tx mscc_felix 0000:00:00.5 swp2: configuring for fixed/sgmii link mode mscc_felix 0000:00:00.5 swp2: Link is Up - 1Gbps/Full - flow control off sja1105 spi2.2 sw2p0: configuring for phy/rgmii-id link mode sja1105 spi2.2 sw2p0: Link is Up - 1Gbps/Full - flow control off pcieport 0000:00:1f.0: AER: Multiple Corrected error received: 0000:00:00.0 pcieport 0000:00:1f.0: AER: can't find device of ID0000 Rob's suggestion is to reimplement the enetc driver workaround as a PCI fixup, and to modify the PCI core to run the fixups for all PCI functions. This change handles the first part. We refactor the common code in enetc_psi_create() and enetc_psi_destroy(), and use the PCI fixup only for those functions for which enetc_pf_probe() won't get called. This avoids some work being done twice for the PFs which are enabled. Fixes: 6fffbc7ae137 ("PCI: Honor firmware's device disabled status") Link: https://lore.kernel.org/netdev/CAL_JsqLsVYiPLx2kcHkDQ4t=hQVCR7NHziDwi9cCFUFhx48Qow@mail.gmail.com/ Suggested-by: Rob Herring Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc_pf.c | 103 +++++++++++++++++------- 1 file changed, 73 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 1416262d4296..d52ac0b6add6 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -1208,50 +1208,81 @@ static int enetc_pf_register_with_ierb(struct pci_dev *pdev) return enetc_ierb_register_pf(ierb_pdev, pdev); } -static int enetc_pf_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static struct enetc_si *enetc_psi_create(struct pci_dev *pdev) { - struct device_node *node = pdev->dev.of_node; - struct enetc_ndev_priv *priv; - struct net_device *ndev; struct enetc_si *si; - struct enetc_pf *pf; int err; - err = enetc_pf_register_with_ierb(pdev); - if (err == -EPROBE_DEFER) - return err; - if (err) - dev_warn(&pdev->dev, - "Could not register with IERB driver: %pe, please update the device tree\n", - ERR_PTR(err)); - - err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf)); - if (err) - return dev_err_probe(&pdev->dev, err, "PCI probing failed\n"); + err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(struct enetc_pf)); + if (err) { + dev_err_probe(&pdev->dev, err, "PCI probing failed\n"); + goto out; + } si = pci_get_drvdata(pdev); if (!si->hw.port || !si->hw.global) { err = -ENODEV; dev_err(&pdev->dev, "could not map PF space, probing a VF?\n"); - goto err_map_pf_space; + goto out_pci_remove; } err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE, &si->cbd_ring); if (err) - goto err_setup_cbdr; + goto out_pci_remove; err = enetc_init_port_rfs_memory(si); if (err) { dev_err(&pdev->dev, "Failed to initialize RFS memory\n"); - goto err_init_port_rfs; + goto out_teardown_cbdr; } err = enetc_init_port_rss_memory(si); if (err) { dev_err(&pdev->dev, "Failed to initialize RSS memory\n"); - goto err_init_port_rss; + goto out_teardown_cbdr; + } + + return si; + +out_teardown_cbdr: + enetc_teardown_cbdr(&si->cbd_ring); +out_pci_remove: + enetc_pci_remove(pdev); +out: + return ERR_PTR(err); +} + +static void enetc_psi_destroy(struct pci_dev *pdev) +{ + struct enetc_si *si = pci_get_drvdata(pdev); + + enetc_teardown_cbdr(&si->cbd_ring); + enetc_pci_remove(pdev); +} + +static int enetc_pf_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device_node *node = pdev->dev.of_node; + struct enetc_ndev_priv *priv; + struct net_device *ndev; + struct enetc_si *si; + struct enetc_pf *pf; + int err; + + err = enetc_pf_register_with_ierb(pdev); + if (err == -EPROBE_DEFER) + return err; + if (err) + dev_warn(&pdev->dev, + "Could not register with IERB driver: %pe, please update the device tree\n", + ERR_PTR(err)); + + si = enetc_psi_create(pdev); + if (IS_ERR(si)) { + err = PTR_ERR(si); + goto err_psi_create; } if (node && !of_device_is_available(node)) { @@ -1339,15 +1370,10 @@ err_alloc_si_res: si->ndev = NULL; free_netdev(ndev); err_alloc_netdev: -err_init_port_rss: -err_init_port_rfs: err_device_disabled: err_setup_mac_addresses: - enetc_teardown_cbdr(&si->cbd_ring); -err_setup_cbdr: -err_map_pf_space: - enetc_pci_remove(pdev); - + enetc_psi_destroy(pdev); +err_psi_create: return err; } @@ -1370,12 +1396,29 @@ static void enetc_pf_remove(struct pci_dev *pdev) enetc_free_msix(priv); enetc_free_si_resources(priv); - enetc_teardown_cbdr(&si->cbd_ring); free_netdev(si->ndev); - enetc_pci_remove(pdev); + enetc_psi_destroy(pdev); +} + +static void enetc_fixup_clear_rss_rfs(struct pci_dev *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct enetc_si *si; + + /* Only apply quirk for disabled functions. For the ones + * that are enabled, enetc_pf_probe() will apply it. + */ + if (node && of_device_is_available(node)) + return; + + si = enetc_psi_create(pdev); + if (si) + enetc_psi_destroy(pdev); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF, + enetc_fixup_clear_rss_rfs); static const struct pci_device_id enetc_pf_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) }, -- cgit v1.2.3 From bfce089ddd0e440d799717cb7312b44faac47983 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 3 Aug 2023 16:58:58 +0300 Subject: net: enetc: remove of_device_is_available() handling Since commit 6fffbc7ae137 ("PCI: Honor firmware's device disabled status"), this is redundant and does nothing, because enetc_pf_probe() no longer even gets called. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc_pf.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index d52ac0b6add6..e0a4cb7e3f50 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -1186,14 +1186,9 @@ static int enetc_init_port_rss_memory(struct enetc_si *si) static int enetc_pf_register_with_ierb(struct pci_dev *pdev) { - struct device_node *node = pdev->dev.of_node; struct platform_device *ierb_pdev; struct device_node *ierb_node; - /* Don't register with the IERB if the PF itself is disabled */ - if (!node || !of_device_is_available(node)) - return 0; - ierb_node = of_find_compatible_node(NULL, NULL, "fsl,ls1028a-enetc-ierb"); if (!ierb_node || !of_device_is_available(ierb_node)) @@ -1285,12 +1280,6 @@ static int enetc_pf_probe(struct pci_dev *pdev, goto err_psi_create; } - if (node && !of_device_is_available(node)) { - dev_info(&pdev->dev, "device is disabled, skipping\n"); - err = -ENODEV; - goto err_device_disabled; - } - pf = enetc_si_priv(si); pf->si = si; pf->total_vfs = pci_sriov_get_totalvfs(pdev); @@ -1370,7 +1359,6 @@ err_alloc_si_res: si->ndev = NULL; free_netdev(ndev); err_alloc_netdev: -err_device_disabled: err_setup_mac_addresses: enetc_psi_destroy(pdev); err_psi_create: -- cgit v1.2.3 From 833bac7ec392bf75053c8a4fa4c36d4148dac77d Mon Sep 17 00:00:00 2001 From: Gerd Bayer Date: Fri, 4 Aug 2023 19:06:23 +0200 Subject: net/smc: Fix setsockopt and sysctl to specify same buffer size again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0227f058aa29 ("net/smc: Unbind r/w buffer size from clcsock and make them tunable") introduced the net.smc.rmem and net.smc.wmem sysctls to specify the size of buffers to be used for SMC type connections. This created a regression for users that specified the buffer size via setsockopt() as the effective buffer size was now doubled. Re-introduce the division by 2 in the SMC buffer create code and level this out by duplicating the net.smc.[rw]mem values used for initializing sk_rcvbuf/sk_sndbuf at socket creation time. This gives users of both methods (setsockopt or sysctl) the effective buffer size that they expect. Initialize net.smc.[rw]mem from its own constant of 64kB, respectively. Internal performance tests show that this value is a good compromise between throughput/latency and memory consumption. Also, this decouples it from any tuning that was done to net.ipv4.tcp_[rw]mem[1] before the module for SMC protocol was loaded. Check that no more than INT_MAX / 2 is assigned to net.smc.[rw]mem, in order to avoid any overflow condition when that is doubled for use in sk_sndbuf or sk_rcvbuf. While at it, drop the confusing sk_buf_size variable from __smc_buf_create and name "compressed" buffer size variables more consistently. Background: Before the commit mentioned above, SMC's buffer allocator in __smc_buf_create() always used half of the sockets' sk_rcvbuf/sk_sndbuf value as initial value to search for appropriate buffers. If the search resorted to using a bigger buffer when all buffers of the specified size were busy, the duplicate of the used effective buffer size is stored back to sk_rcvbuf/sk_sndbuf. When available, buffers of exactly the size that a user had specified as input to setsockopt() were used, despite setsockopt()'s documentation in "man 7 socket" talking of a mandatory duplication: [...] SO_SNDBUF Sets or gets the maximum socket send buffer in bytes. The kernel doubles this value (to allow space for book‐ keeping overhead) when it is set using setsockopt(2), and this doubled value is returned by getsockopt(2). The default value is set by the /proc/sys/net/core/wmem_default file and the maximum allowed value is set by the /proc/sys/net/core/wmem_max file. The minimum (doubled) value for this option is 2048. [...] Fixes: 0227f058aa29 ("net/smc: Unbind r/w buffer size from clcsock and make them tunable") Co-developed-by: Jan Karcher Signed-off-by: Jan Karcher Reviewed-by: Wenjia Zhang Reviewed-by: Tony Lu Signed-off-by: Gerd Bayer Signed-off-by: David S. Miller --- net/smc/af_smc.c | 4 ++-- net/smc/smc.h | 2 +- net/smc/smc_clc.c | 4 ++-- net/smc/smc_core.c | 25 ++++++++++++------------- net/smc/smc_sysctl.c | 10 ++++++++-- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 0c013d2b5d8f..5b878e523abf 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -378,8 +378,8 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, sk->sk_state = SMC_INIT; sk->sk_destruct = smc_destruct; sk->sk_protocol = protocol; - WRITE_ONCE(sk->sk_sndbuf, READ_ONCE(net->smc.sysctl_wmem)); - WRITE_ONCE(sk->sk_rcvbuf, READ_ONCE(net->smc.sysctl_rmem)); + WRITE_ONCE(sk->sk_sndbuf, 2 * READ_ONCE(net->smc.sysctl_wmem)); + WRITE_ONCE(sk->sk_rcvbuf, 2 * READ_ONCE(net->smc.sysctl_rmem)); smc = smc_sk(sk); INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); INIT_WORK(&smc->connect_work, smc_connect_work); diff --git a/net/smc/smc.h b/net/smc/smc.h index 2eeea4cdc718..1f2b912c43d1 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h @@ -161,7 +161,7 @@ struct smc_connection { struct smc_buf_desc *sndbuf_desc; /* send buffer descriptor */ struct smc_buf_desc *rmb_desc; /* RMBE descriptor */ - int rmbe_size_short;/* compressed notation */ + int rmbe_size_comp; /* compressed notation */ int rmbe_update_limit; /* lower limit for consumer * cursor update diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index b9b8b07aa702..c90d9e5dda54 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -1007,7 +1007,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, clc->d0.gid = conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd); clc->d0.token = conn->rmb_desc->token; - clc->d0.dmbe_size = conn->rmbe_size_short; + clc->d0.dmbe_size = conn->rmbe_size_comp; clc->d0.dmbe_idx = 0; memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE); if (version == SMC_V1) { @@ -1050,7 +1050,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu); break; } - clc->r0.rmbe_size = conn->rmbe_size_short; + clc->r0.rmbe_size = conn->rmbe_size_comp; clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ? cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) : cpu_to_be64((u64)sg_dma_address diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 3f465faf2b68..6b78075404d7 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -2309,31 +2309,30 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) struct smc_connection *conn = &smc->conn; struct smc_link_group *lgr = conn->lgr; struct list_head *buf_list; - int bufsize, bufsize_short; + int bufsize, bufsize_comp; struct rw_semaphore *lock; /* lock buffer list */ bool is_dgraded = false; - int sk_buf_size; if (is_rmb) /* use socket recv buffer size (w/o overhead) as start value */ - sk_buf_size = smc->sk.sk_rcvbuf; + bufsize = smc->sk.sk_rcvbuf / 2; else /* use socket send buffer size (w/o overhead) as start value */ - sk_buf_size = smc->sk.sk_sndbuf; + bufsize = smc->sk.sk_sndbuf / 2; - for (bufsize_short = smc_compress_bufsize(sk_buf_size, is_smcd, is_rmb); - bufsize_short >= 0; bufsize_short--) { + for (bufsize_comp = smc_compress_bufsize(bufsize, is_smcd, is_rmb); + bufsize_comp >= 0; bufsize_comp--) { if (is_rmb) { lock = &lgr->rmbs_lock; - buf_list = &lgr->rmbs[bufsize_short]; + buf_list = &lgr->rmbs[bufsize_comp]; } else { lock = &lgr->sndbufs_lock; - buf_list = &lgr->sndbufs[bufsize_short]; + buf_list = &lgr->sndbufs[bufsize_comp]; } - bufsize = smc_uncompress_bufsize(bufsize_short); + bufsize = smc_uncompress_bufsize(bufsize_comp); /* check for reusable slot in the link group */ - buf_desc = smc_buf_get_slot(bufsize_short, lock, buf_list); + buf_desc = smc_buf_get_slot(bufsize_comp, lock, buf_list); if (buf_desc) { buf_desc->is_dma_need_sync = 0; SMC_STAT_RMB_SIZE(smc, is_smcd, is_rmb, bufsize); @@ -2377,8 +2376,8 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) if (is_rmb) { conn->rmb_desc = buf_desc; - conn->rmbe_size_short = bufsize_short; - smc->sk.sk_rcvbuf = bufsize; + conn->rmbe_size_comp = bufsize_comp; + smc->sk.sk_rcvbuf = bufsize * 2; atomic_set(&conn->bytes_to_rcv, 0); conn->rmbe_update_limit = smc_rmb_wnd_update_limit(buf_desc->len); @@ -2386,7 +2385,7 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) smc_ism_set_conn(conn); /* map RMB/smcd_dev to conn */ } else { conn->sndbuf_desc = buf_desc; - smc->sk.sk_sndbuf = bufsize; + smc->sk.sk_sndbuf = bufsize * 2; atomic_set(&conn->sndbuf_space, bufsize); } return 0; diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c index b6f79fabb9d3..0b2a957ca5f5 100644 --- a/net/smc/smc_sysctl.c +++ b/net/smc/smc_sysctl.c @@ -21,6 +21,10 @@ static int min_sndbuf = SMC_BUF_MIN_SIZE; static int min_rcvbuf = SMC_BUF_MIN_SIZE; +static int max_sndbuf = INT_MAX / 2; +static int max_rcvbuf = INT_MAX / 2; +static const int net_smc_wmem_init = (64 * 1024); +static const int net_smc_rmem_init = (64 * 1024); static struct ctl_table smc_table[] = { { @@ -53,6 +57,7 @@ static struct ctl_table smc_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &min_sndbuf, + .extra2 = &max_sndbuf, }, { .procname = "rmem", @@ -61,6 +66,7 @@ static struct ctl_table smc_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &min_rcvbuf, + .extra2 = &max_rcvbuf, }, { } }; @@ -88,8 +94,8 @@ int __net_init smc_sysctl_net_init(struct net *net) net->smc.sysctl_autocorking_size = SMC_AUTOCORKING_DEFAULT_SIZE; net->smc.sysctl_smcr_buf_type = SMCR_PHYS_CONT_BUFS; net->smc.sysctl_smcr_testlink_time = SMC_LLC_TESTLINK_DEFAULT_TIME; - WRITE_ONCE(net->smc.sysctl_wmem, READ_ONCE(net->ipv4.sysctl_tcp_wmem[1])); - WRITE_ONCE(net->smc.sysctl_rmem, READ_ONCE(net->ipv4.sysctl_tcp_rmem[1])); + WRITE_ONCE(net->smc.sysctl_wmem, net_smc_wmem_init); + WRITE_ONCE(net->smc.sysctl_rmem, net_smc_rmem_init); return 0; -- cgit v1.2.3 From 30c3c4a4497c3765bf6b298f5072c8165aeaf7cc Mon Sep 17 00:00:00 2001 From: Gerd Bayer Date: Fri, 4 Aug 2023 19:06:24 +0200 Subject: net/smc: Use correct buffer sizes when switching between TCP and SMC Tuning of the effective buffer size through setsockopts was working for SMC traffic only but not for TCP fall-back connections even before commit 0227f058aa29 ("net/smc: Unbind r/w buffer size from clcsock and make them tunable"). That change made it apparent that TCP fall-back connections would use net.smc.[rw]mem as buffer size instead of net.ipv4_tcp_[rw]mem. Amend the code that copies attributes between the (TCP) clcsock and the SMC socket and adjust buffer sizes appropriately: - Copy over sk_userlocks so that both sockets agree on whether tuning via setsockopt is active. - When falling back to TCP use sk_sndbuf or sk_rcvbuf as specified with setsockopt. Otherwise, use the sysctl value for TCP/IPv4. - Likewise, use either values from setsockopt or from sysctl for SMC (duplicated) on successful SMC connect. In smc_tcp_listen_work() drop the explicit copy of buffer sizes as that is taken care of by the attribute copy. Fixes: 0227f058aa29 ("net/smc: Unbind r/w buffer size from clcsock and make them tunable") Reviewed-by: Wenjia Zhang Reviewed-by: Tony Lu Signed-off-by: Gerd Bayer Signed-off-by: David S. Miller --- net/smc/af_smc.c | 73 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 5b878e523abf..f5834af5fad5 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -436,13 +436,60 @@ out: return rc; } +/* copy only relevant settings and flags of SOL_SOCKET level from smc to + * clc socket (since smc is not called for these options from net/core) + */ + +#define SK_FLAGS_SMC_TO_CLC ((1UL << SOCK_URGINLINE) | \ + (1UL << SOCK_KEEPOPEN) | \ + (1UL << SOCK_LINGER) | \ + (1UL << SOCK_BROADCAST) | \ + (1UL << SOCK_TIMESTAMP) | \ + (1UL << SOCK_DBG) | \ + (1UL << SOCK_RCVTSTAMP) | \ + (1UL << SOCK_RCVTSTAMPNS) | \ + (1UL << SOCK_LOCALROUTE) | \ + (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \ + (1UL << SOCK_RXQ_OVFL) | \ + (1UL << SOCK_WIFI_STATUS) | \ + (1UL << SOCK_NOFCS) | \ + (1UL << SOCK_FILTER_LOCKED) | \ + (1UL << SOCK_TSTAMP_NEW)) + +/* if set, use value set by setsockopt() - else use IPv4 or SMC sysctl value */ +static void smc_adjust_sock_bufsizes(struct sock *nsk, struct sock *osk, + unsigned long mask) +{ + struct net *nnet = sock_net(nsk); + + nsk->sk_userlocks = osk->sk_userlocks; + if (osk->sk_userlocks & SOCK_SNDBUF_LOCK) { + nsk->sk_sndbuf = osk->sk_sndbuf; + } else { + if (mask == SK_FLAGS_SMC_TO_CLC) + WRITE_ONCE(nsk->sk_sndbuf, + READ_ONCE(nnet->ipv4.sysctl_tcp_wmem[1])); + else + WRITE_ONCE(nsk->sk_sndbuf, + 2 * READ_ONCE(nnet->smc.sysctl_wmem)); + } + if (osk->sk_userlocks & SOCK_RCVBUF_LOCK) { + nsk->sk_rcvbuf = osk->sk_rcvbuf; + } else { + if (mask == SK_FLAGS_SMC_TO_CLC) + WRITE_ONCE(nsk->sk_rcvbuf, + READ_ONCE(nnet->ipv4.sysctl_tcp_rmem[1])); + else + WRITE_ONCE(nsk->sk_rcvbuf, + 2 * READ_ONCE(nnet->smc.sysctl_rmem)); + } +} + static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, unsigned long mask) { /* options we don't get control via setsockopt for */ nsk->sk_type = osk->sk_type; - nsk->sk_sndbuf = osk->sk_sndbuf; - nsk->sk_rcvbuf = osk->sk_rcvbuf; nsk->sk_sndtimeo = osk->sk_sndtimeo; nsk->sk_rcvtimeo = osk->sk_rcvtimeo; nsk->sk_mark = READ_ONCE(osk->sk_mark); @@ -453,26 +500,10 @@ static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, nsk->sk_flags &= ~mask; nsk->sk_flags |= osk->sk_flags & mask; + + smc_adjust_sock_bufsizes(nsk, osk, mask); } -#define SK_FLAGS_SMC_TO_CLC ((1UL << SOCK_URGINLINE) | \ - (1UL << SOCK_KEEPOPEN) | \ - (1UL << SOCK_LINGER) | \ - (1UL << SOCK_BROADCAST) | \ - (1UL << SOCK_TIMESTAMP) | \ - (1UL << SOCK_DBG) | \ - (1UL << SOCK_RCVTSTAMP) | \ - (1UL << SOCK_RCVTSTAMPNS) | \ - (1UL << SOCK_LOCALROUTE) | \ - (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \ - (1UL << SOCK_RXQ_OVFL) | \ - (1UL << SOCK_WIFI_STATUS) | \ - (1UL << SOCK_NOFCS) | \ - (1UL << SOCK_FILTER_LOCKED) | \ - (1UL << SOCK_TSTAMP_NEW)) -/* copy only relevant settings and flags of SOL_SOCKET level from smc to - * clc socket (since smc is not called for these options from net/core) - */ static void smc_copy_sock_settings_to_clc(struct smc_sock *smc) { smc_copy_sock_settings(smc->clcsock->sk, &smc->sk, SK_FLAGS_SMC_TO_CLC); @@ -2479,8 +2510,6 @@ static void smc_tcp_listen_work(struct work_struct *work) sock_hold(lsk); /* sock_put in smc_listen_work */ INIT_WORK(&new_smc->smc_listen_work, smc_listen_work); smc_copy_sock_settings_to_smc(new_smc); - new_smc->sk.sk_sndbuf = lsmc->sk.sk_sndbuf; - new_smc->sk.sk_rcvbuf = lsmc->sk.sk_rcvbuf; sock_hold(&new_smc->sk); /* sock_put in passive closing */ if (!queue_work(smc_hs_wq, &new_smc->smc_listen_work)) sock_put(&new_smc->sk); -- cgit v1.2.3 From 1a5ca2aad7b907f9d7101eaba7dfa068b2da3bdd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 9 Aug 2023 01:07:45 +0000 Subject: ASoC: rsnd: call of_node_put() when break We need to call of_node_put() when break from for_each_child_of_node(). This patch add missing of_node_put(). Reported-by: kernel test robot Reported-by: Julia Lawall Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkfh9g68.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9f3d97bc177a..cf2031b7e209 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1293,6 +1293,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); + of_node_put(node); break; } } @@ -1312,6 +1313,7 @@ audio_graph: i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); + of_node_put(node); break; } } -- cgit v1.2.3 From 48c6253fefa38556e0c5c2942edd9181529407e4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Aug 2023 12:04:46 +0200 Subject: ASoC: samsung: midas_wm1811: Fix 'Headphone Switch' control creation 'Headphone Switch' control is already registered from sound/soc/codecs/wm_hubs.c:479, so duplicating it in midas_wm1811 causes following probe failure: midas-audio sound: control 2:0:0:Headphone Switch:0 is already present midas-audio sound: ASoC: Failed to add Headphone Switch: -16 midas-audio sound: Failed to register card: -16 midas-audio: probe of sound failed with error -16 Fix this by dropping duplicated control. Fixes: d27224a45e54 ("ASoC: samsung: midas_wm1811: Map missing jack kcontrols") Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230809100446.2105825-1-m.szyprowski@samsung.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 44b32f5cddca..126098fdcf1b 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -257,7 +257,6 @@ static const struct snd_kcontrol_new midas_controls[] = { SOC_DAPM_PIN_SWITCH("Main Mic"), SOC_DAPM_PIN_SWITCH("Sub Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("FM In"), }; -- cgit v1.2.3 From 43dae319b50fac075ad864f84501c703ef20eb2b Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 8 Aug 2023 11:44:05 +0100 Subject: drm/rockchip: Don't spam logs in atomic check Userspace should not be able to trigger DRM_ERROR messages to spam the logs; especially not through atomic commit parameters which are completely legitimate for userspace to attempt. Signed-off-by: Daniel Stone Fixes: 7707f7227f09 ("drm/rockchip: Add support for afbc") Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20230808104405.522493-1-daniels@collabora.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index a530ecc4d207..bf34498c1b6d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -833,12 +833,12 @@ static int vop_plane_atomic_check(struct drm_plane *plane, * need align with 2 pixel. */ if (fb->format->is_yuv && ((new_plane_state->src.x1 >> 16) % 2)) { - DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n"); + DRM_DEBUG_KMS("Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; } if (fb->format->is_yuv && new_plane_state->rotation & DRM_MODE_REFLECT_Y) { - DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n"); + DRM_DEBUG_KMS("Invalid Source: Yuv format does not support this rotation\n"); return -EINVAL; } @@ -846,7 +846,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, struct vop *vop = to_vop(crtc); if (!vop->data->afbc) { - DRM_ERROR("vop does not support AFBC\n"); + DRM_DEBUG_KMS("vop does not support AFBC\n"); return -EINVAL; } @@ -855,15 +855,16 @@ static int vop_plane_atomic_check(struct drm_plane *plane, return ret; if (new_plane_state->src.x1 || new_plane_state->src.y1) { - DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n", - new_plane_state->src.x1, - new_plane_state->src.y1, fb->offsets[0]); + DRM_DEBUG_KMS("AFBC does not support offset display, " \ + "xpos=%d, ypos=%d, offset=%d\n", + new_plane_state->src.x1, new_plane_state->src.y1, + fb->offsets[0]); return -EINVAL; } if (new_plane_state->rotation && new_plane_state->rotation != DRM_MODE_ROTATE_0) { - DRM_ERROR("No rotation support in AFBC, rotation=%d\n", - new_plane_state->rotation); + DRM_DEBUG_KMS("No rotation support in AFBC, rotation=%d\n", + new_plane_state->rotation); return -EINVAL; } } -- cgit v1.2.3 From 24138933b97b055d486e8064b4a1721702442a9b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 9 Aug 2023 14:31:15 +0200 Subject: netfilter: nf_tables: don't skip expired elements during walk There is an asymmetry between commit/abort and preparation phase if the following conditions are met: 1. set is a verdict map ("1.2.3.4 : jump foo") 2. timeouts are enabled In this case, following sequence is problematic: 1. element E in set S refers to chain C 2. userspace requests removal of set S 3. kernel does a set walk to decrement chain->use count for all elements from preparation phase 4. kernel does another set walk to remove elements from the commit phase (or another walk to do a chain->use increment for all elements from abort phase) If E has already expired in 1), it will be ignored during list walk, so its use count won't have been changed. Then, when set is culled, ->destroy callback will zap the element via nf_tables_set_elem_destroy(), but this function is only safe for elements that have been deactivated earlier from the preparation phase: lack of earlier deactivate removes the element but leaks the chain use count, which results in a WARN splat when the chain gets removed later, plus a leak of the nft_chain structure. Update pipapo_get() not to skip expired elements, otherwise flush command reports bogus ENOENT errors. Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges") Fixes: 8d8540c4f5e0 ("netfilter: nft_set_rbtree: add timeout support") Fixes: 9d0982927e79 ("netfilter: nft_hash: add support for timeouts") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 4 ++++ net/netfilter/nft_set_hash.c | 2 -- net/netfilter/nft_set_pipapo.c | 18 ++++++++++++------ net/netfilter/nft_set_rbtree.c | 2 -- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d3c6ecd1f5a6..b4321869e5c6 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5602,8 +5602,12 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx, const struct nft_set_iter *iter, struct nft_set_elem *elem) { + const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); struct nft_set_dump_args *args; + if (nft_set_elem_expired(ext)) + return 0; + args = container_of(iter, struct nft_set_dump_args, iter); return nf_tables_fill_setelem(args->skb, set, elem, args->reset); } diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 0b73cb0e752f..24caa31fa231 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -278,8 +278,6 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set, if (iter->count < iter->skip) goto cont; - if (nft_set_elem_expired(&he->ext)) - goto cont; if (!nft_set_elem_active(&he->ext, iter->genmask)) goto cont; diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 49915a2a58eb..d54784ea465b 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -566,8 +566,7 @@ next_match: goto out; if (last) { - if (nft_set_elem_expired(&f->mt[b].e->ext) || - (genmask && + if ((genmask && !nft_set_elem_active(&f->mt[b].e->ext, genmask))) goto next_match; @@ -601,8 +600,17 @@ out: static void *nft_pipapo_get(const struct net *net, const struct nft_set *set, const struct nft_set_elem *elem, unsigned int flags) { - return pipapo_get(net, set, (const u8 *)elem->key.val.data, - nft_genmask_cur(net)); + struct nft_pipapo_elem *ret; + + ret = pipapo_get(net, set, (const u8 *)elem->key.val.data, + nft_genmask_cur(net)); + if (IS_ERR(ret)) + return ret; + + if (nft_set_elem_expired(&ret->ext)) + return ERR_PTR(-ENOENT); + + return ret; } /** @@ -2005,8 +2013,6 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, goto cont; e = f->mt[r].e; - if (nft_set_elem_expired(&e->ext)) - goto cont; elem.priv = e; diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index 8d73fffd2d09..39956e5341c9 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -552,8 +552,6 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, if (iter->count < iter->skip) goto cont; - if (nft_set_elem_expired(&rbe->ext)) - goto cont; if (!nft_set_elem_active(&rbe->ext, iter->genmask)) goto cont; -- cgit v1.2.3 From 6311071a056272e1e761de8d0305e87cc566f734 Mon Sep 17 00:00:00 2001 From: Keith Yeo Date: Mon, 31 Jul 2023 11:47:20 +0800 Subject: wifi: nl80211: fix integer overflow in nl80211_parse_mbssid_elems() nl80211_parse_mbssid_elems() uses a u8 variable num_elems to count the number of MBSSID elements in the nested netlink attribute attrs, which can lead to an integer overflow if a user of the nl80211 interface specifies 256 or more elements in the corresponding attribute in userspace. The integer overflow can lead to a heap buffer overflow as num_elems determines the size of the trailing array in elems, and this array is thereafter written to for each element in attrs. Note that this vulnerability only affects devices with the wiphy->mbssid_max_interfaces member set for the wireless physical device struct in the device driver, and can only be triggered by a process with CAP_NET_ADMIN capabilities. Fix this by checking for a maximum of 255 elements in attrs. Cc: stable@vger.kernel.org Fixes: dc1e3cb8da8b ("nl80211: MBSSID and EMA support in AP mode") Signed-off-by: Keith Yeo Link: https://lore.kernel.org/r/20230731034719.77206-1-keithyjy@gmail.com Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0da2e6a2a7ea..8bcf8e293308 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5430,8 +5430,11 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) if (!wiphy->mbssid_max_interfaces) return ERR_PTR(-EINVAL); - nla_for_each_nested(nl_elems, attrs, rem_elems) + nla_for_each_nested(nl_elems, attrs, rem_elems) { + if (num_elems >= 255) + return ERR_PTR(-EINVAL); num_elems++; + } elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); if (!elems) -- cgit v1.2.3 From 06f2ab86a5b6ed55f013258de4be9319841853ea Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 9 Aug 2023 04:12:41 -0400 Subject: wifi: ath12k: Fix buffer overflow when scanning with extraie If cfg80211 is providing extraie's for a scanning process then ath12k will copy that over to the firmware. The extraie.len is a 32 bit value in struct element_info and describes the amount of bytes for the vendor information elements. The problem is the allocation of the buffer. It has to align the TLV sections by 4 bytes. But the code was using an u8 to store the newly calculated length of this section (with alignment). And the new calculated length was then used to allocate the skbuff. But the actual code to copy in the data is using the extraie.len and not the calculated "aligned" length. The length of extraie with IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS enabled was 264 bytes during tests with a wifi card. But it only allocated 8 bytes (264 bytes % 256) for it. As consequence, the code to memcpy the extraie into the skb was then just overwriting data after skb->end. Things like shinfo were therefore corrupted. This could usually be seen by a crash in skb_zcopy_clear which tried to call a ubuf_info callback (using a bogus address). Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Link: https://lore.kernel.org/r/20230809081241.32765-1-quic_wgong@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath12k/wmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 6512267ae4ca..4928e4e91660 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2144,8 +2144,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar, struct wmi_tlv *tlv; void *ptr; int i, ret, len; - u32 *tmp_ptr; - u8 extraie_len_with_pad = 0; + u32 *tmp_ptr, extraie_len_with_pad = 0; struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL; struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL; -- cgit v1.2.3 From 08fffa74d9772d9538338be3f304006c94dde6f0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 27 Jul 2023 10:22:20 -0500 Subject: drm/amd: Disable S/G for APUs when 64GB or more host memory Users report a white flickering screen on multiple systems that is tied to having 64GB or more memory. When S/G is enabled pages will get pinned to both VRAM carve out and system RAM leading to this. Until it can be fixed properly, disable S/G when 64GB of memory or more is detected. This will force pages to be pinned into VRAM. This should fix white screen flickers but if VRAM pressure is encountered may lead to black screens. It's a trade-off for now. Fixes: 81d0bcf99009 ("drm/amdgpu: make display pinning more flexible (v2)") Cc: Hamza Mahfooz Cc: Roman Li Cc: # 6.1.y: bf0207e172703 ("drm/amdgpu: add S/G display parameter") Cc: # 6.4.y Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2735 Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2354 Signed-off-by: Mario Limonciello Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 26 +++++++++++++++++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index a3b86b86dc47..6dc950c1b689 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1296,6 +1296,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, void amdgpu_device_pci_config_reset(struct amdgpu_device *adev); int amdgpu_device_pci_reset(struct amdgpu_device *adev); bool amdgpu_device_need_post(struct amdgpu_device *adev); +bool amdgpu_sg_display_supported(struct amdgpu_device *adev); bool amdgpu_device_pcie_dynamic_switching_supported(void); bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev); bool amdgpu_device_aspm_support_quirk(void); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a2cdde0ca0a7..45e9d737e5b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1458,6 +1458,32 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) return true; } +/* + * On APUs with >= 64GB white flickering has been observed w/ SG enabled. + * Disable S/G on such systems until we have a proper fix. + * https://gitlab.freedesktop.org/drm/amd/-/issues/2354 + * https://gitlab.freedesktop.org/drm/amd/-/issues/2735 + */ +bool amdgpu_sg_display_supported(struct amdgpu_device *adev) +{ + switch (amdgpu_sg_display) { + case -1: + break; + case 0: + return false; + case 1: + return true; + default: + return false; + } + if ((totalram_pages() << (PAGE_SHIFT - 10)) + + (adev->gmc.real_vram_size / 1024) >= 64000000) { + DRM_WARN("Disabling S/G due to >=64GB RAM\n"); + return false; + } + return true; +} + /* * Intel hosts such as Raptor Lake and Sapphire Rapids don't support dynamic * speed switching. Until we have confirmation from Intel that a specific host diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0fa739fd6a9c..e5554a36e8c8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1638,9 +1638,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } break; } - if (init_data.flags.gpu_vm_support && - (amdgpu_sg_display == 0)) - init_data.flags.gpu_vm_support = false; + if (init_data.flags.gpu_vm_support) + init_data.flags.gpu_vm_support = amdgpu_sg_display_supported(adev); if (init_data.flags.gpu_vm_support) adev->mode_info.gpu_vm_support = true; -- cgit v1.2.3 From 730d44e1fa306a20746ad4a85da550662aed9daa Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Thu, 27 Jul 2023 09:59:45 +0800 Subject: drm/amd/pm: skip the RLC stop when S0i3 suspend for SMU v13.0.4/11 For SMU v13.0.4/11, driver does not need to stop RLC for S0i3, the firmwares will handle that properly. Signed-off-by: Tim Huang Reviewed-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ce41a8309582..222af2fae745 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1581,9 +1581,9 @@ static int smu_disable_dpms(struct smu_context *smu) /* * For SMU 13.0.4/11, PMFW will handle the features disablement properly - * for gpu reset case. Driver involvement is unnecessary. + * for gpu reset and S0i3 cases. Driver involvement is unnecessary. */ - if (amdgpu_in_reset(adev)) { + if (amdgpu_in_reset(adev) || adev->in_s0ix) { switch (adev->ip_versions[MP1_HWIP][0]) { case IP_VERSION(13, 0, 4): case IP_VERSION(13, 0, 11): -- cgit v1.2.3 From d3de41ee5febe5c2d9989fe9810bce2bb54a3a8e Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 25 Jul 2023 19:11:54 +0530 Subject: drm/amdgpu: Match against exact bootloader status On PSP v13.x ASICs, boot loader will set only the MSB to 1 and clear the least significant bits for any command submission. Hence match against the exact register value, otherwise a register value of all 0xFFs also could falsely indicate that boot loader is ready. Also, from PSP v13.0.6 and newer, bits[7:0] will be used to indicate command error status. Signed-off-by: Lijo Lazar Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index e1a392bcea70..af5685f4cb34 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -137,14 +137,15 @@ static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) int ret; int retry_loop; + /* Wait for bootloader to signify that it is ready having bit 31 of + * C2PMSG_35 set to 1. All other bits are expected to be cleared. + * If there is an error in processing command, bits[7:0] will be set. + * This is applicable for PSP v13.0.6 and newer. + */ for (retry_loop = 0; retry_loop < 10; retry_loop++) { - /* Wait for bootloader to signify that is - ready having bit 31 of C2PMSG_35 set to 1 */ - ret = psp_wait_for(psp, - SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), - 0x80000000, - 0x80000000, - false); + ret = psp_wait_for( + psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), + 0x80000000, 0xffffffff, false); if (ret == 0) return 0; -- cgit v1.2.3 From 7ad1dfc144cbf62702fd07838da8fd8a77921083 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 31 Jul 2023 09:22:05 -0500 Subject: drm/amd/display: Don't show stack trace for missing eDP Some systems are only connected by HDMI or DP, so warning related to missing eDP is unnecessary. Downgrade to debug instead. Cc: Hamza Mahfooz Fixes: 6d9b6dceaa51 ("drm/amd/display: only warn once in dce110_edp_wait_for_hpd_ready()") Reported-by: Mastan.Katragadda@amd.com Signed-off-by: Mario Limonciello Reviewed-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 20d4d08a6a2f..6966420dfbac 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -777,7 +777,8 @@ void dce110_edp_wait_for_hpd_ready( dal_gpio_destroy_irq(&hpd); /* ensure that the panel is detected */ - ASSERT(edp_hpd_high); + if (!edp_hpd_high) + DC_LOG_DC("%s: wait timed out!\n", __func__); } void dce110_edp_power_control( -- cgit v1.2.3 From bd60e2eafd8fb053948b6e23e8167baf7a159750 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Thu, 27 Jul 2023 19:37:31 +0800 Subject: drm/amd/pm: correct the pcie width for smu 13.0.0 correct the pcie width value in pp_dpm_pcie for smu 13.0.0 Signed-off-by: Kenneth Feng Reviewed-by: Harish Kasiviswanathan Acked-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 3d188616ba24..e191bbe9e994 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -1140,7 +1140,6 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, (OverDriveTableExternal_t *)smu->smu_table.overdrive_table; struct smu_13_0_dpm_table *single_dpm_table; struct smu_13_0_pcie_table *pcie_table; - const int link_width[] = {0, 1, 2, 4, 8, 12, 16}; uint32_t gen_speed, lane_width; int i, curr_freq, size = 0; int32_t min_value, max_value; @@ -1256,7 +1255,7 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_lane[i] == 6) ? "x16" : "", pcie_table->clk_freq[i], (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && - (lane_width == DECODE_LANE_WIDTH(link_width[pcie_table->pcie_lane[i]])) ? + (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? "*" : ""); break; -- cgit v1.2.3 From 61319b8e3b58a7167cf146313fd4523fe72586bc Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Fri, 21 Jul 2023 19:18:00 +0800 Subject: drm/amd/pm: disable the SMU13 OD feature support temporarily The existing OD interface cannot support the growing demand for more OD features. We are in the transition to a new OD mechanism. So, disable the SMU13 OD feature support temporarily. And this should be reverted when the new OD mechanism online. Signed-off-by: Evan Quan Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 17 ++++++++++++++--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 12 +++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index e191bbe9e994..fddcd834bcec 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -331,11 +331,13 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu) struct smu_13_0_0_powerplay_table *powerplay_table = table_context->power_play_table; struct smu_baco_context *smu_baco = &smu->smu_baco; +#if 0 PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; const OverDriveLimits_t * const overdrive_lowerlimits = &pptable->SkuTable.OverDriveLimitsMin; +#endif if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_HARDWAREDC) smu->dc_controlled_by_gpio = true; @@ -347,18 +349,27 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu) if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO) smu_baco->maco_support = true; + /* + * We are in the transition to a new OD mechanism. + * Disable the OD feature support for SMU13 temporarily. + * TODO: get this reverted when new OD mechanism online + */ +#if 0 if (!overdrive_lowerlimits->FeatureCtrlMask || !overdrive_upperlimits->FeatureCtrlMask) smu->od_enabled = false; - table_context->thermal_controller_type = - powerplay_table->thermal_controller_type; - /* * Instead of having its own buffer space and get overdrive_table copied, * smu->od_settings just points to the actual overdrive_table */ smu->od_settings = &powerplay_table->overdrive_table; +#else + smu->od_enabled = false; +#endif + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index b1f0937ccade..62f2886ab4df 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -323,10 +323,12 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu) struct smu_baco_context *smu_baco = &smu->smu_baco; PPTable_t *smc_pptable = table_context->driver_pptable; BoardTable_t *BoardTable = &smc_pptable->BoardTable; +#if 0 const OverDriveLimits_t * const overdrive_upperlimits = &smc_pptable->SkuTable.OverDriveLimitsBasicMax; const OverDriveLimits_t * const overdrive_lowerlimits = &smc_pptable->SkuTable.OverDriveLimitsMin; +#endif if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_HARDWAREDC) smu->dc_controlled_by_gpio = true; @@ -338,18 +340,22 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu) if (smu_baco->platform_support && (BoardTable->HsrEnabled || BoardTable->VddqOffEnabled)) smu_baco->maco_support = true; +#if 0 if (!overdrive_lowerlimits->FeatureCtrlMask || !overdrive_upperlimits->FeatureCtrlMask) smu->od_enabled = false; - table_context->thermal_controller_type = - powerplay_table->thermal_controller_type; - /* * Instead of having its own buffer space and get overdrive_table copied, * smu->od_settings just points to the actual overdrive_table */ smu->od_settings = &powerplay_table->overdrive_table; +#else + smu->od_enabled = false; +#endif + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; return 0; } -- cgit v1.2.3 From 96b020e2163fb2197266b2f71b1007495206e6bb Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Mon, 31 Jul 2023 07:35:05 -0100 Subject: drm/amd/display: check attr flag before set cursor degamma on DCN3+ Don't set predefined degamma curve to cursor plane if the cursor attribute flag is not set. Applying a degamma curve to the cursor by default breaks userspace expectation. Checking the flag before performing any color transformation prevents too dark cursor gamma in DCN3+ on many Linux desktop environment (KDE Plasma, GNOME, wlroots-based, etc.) as reported at: - https://gitlab.freedesktop.org/drm/amd/-/issues/1513 This is the same approach followed by DCN2 drivers where the issue is not present. Fixes: 03f54d7d3448 ("drm/amd/display: Add DCN3 DPP") Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1513 Signed-off-by: Melissa Wen Reviewed-by: Harry Wentland Tested-by: Alex Hung Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c index e5b7ef7422b8..50dc83404644 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c @@ -357,8 +357,11 @@ void dpp3_set_cursor_attributes( int cur_rom_en = 0; if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || - color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) - cur_rom_en = 1; + color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { + if (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) { + cur_rom_en = 1; + } + } REG_UPDATE_3(CURSOR0_CONTROL, CUR0_MODE, color_format, -- cgit v1.2.3 From a73ea79a0c94bacfab4df23a1043644d14f56591 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 2 Aug 2023 10:24:36 +0530 Subject: drm/amd/pm: Fix SMU v13.0.6 energy reporting Energy counter should be reported in units of 15.259 uJ. Don't apply any conversion. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 1ac552142763..fe4ee2daa5d8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1993,9 +1993,8 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table gpu_metrics->average_socket_power = SMUQ10_TO_UINT(metrics->SocketPower); - /* Energy is reported in 15.625mJ units */ - gpu_metrics->energy_accumulator = - SMUQ10_TO_UINT(metrics->SocketEnergyAcc); + /* Energy counter reported in 15.259uJ (2^-16) units */ + gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc; gpu_metrics->current_gfxclk = SMUQ10_TO_UINT(metrics->GfxclkFrequency[xcc0]); -- cgit v1.2.3 From 77245f1c3c6495521f6a3af082696ee2f8ce3921 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sat, 5 Aug 2023 00:06:43 +0200 Subject: x86/CPU/AMD: Do not leak quotient data after a division by 0 Under certain circumstances, an integer division by 0 which faults, can leave stale quotient data from a previous division operation on Zen1 microarchitectures. Do a dummy division 0/1 before returning from the #DE exception handler in order to avoid any leaks of potentially sensitive data. Signed-off-by: Borislav Petkov (AMD) Cc: Signed-off-by: Linus Torvalds --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/processor.h | 2 ++ arch/x86/kernel/cpu/amd.c | 19 +++++++++++++++++++ arch/x86/kernel/traps.c | 2 ++ 4 files changed, 24 insertions(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 094f88fee536..b69b0d7756aa 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -495,4 +495,5 @@ /* BUG word 2 */ #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ +#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 7c67db7c9f53..973db0406528 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -683,10 +683,12 @@ extern u16 get_llc_id(unsigned int cpu); extern u32 amd_get_nodes_per_socket(void); extern u32 amd_get_highest_perf(void); extern bool cpu_has_ibpb_brtype_microcode(void); +extern void amd_clear_divider(void); #else static inline u32 amd_get_nodes_per_socket(void) { return 0; } static inline u32 amd_get_highest_perf(void) { return 0; } static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; } +static inline void amd_clear_divider(void) { } #endif extern unsigned long arch_align_stack(unsigned long sp); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 1e1e253038ce..b55d8f82b621 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -75,6 +75,10 @@ static const int amd_zenbleed[] = AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); +static const int amd_div0[] = + AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf), + AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf)); + static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) { int osvw_id = *erratum++; @@ -1130,6 +1134,11 @@ static void init_amd(struct cpuinfo_x86 *c) WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS)); zenbleed_check(c); + + if (cpu_has_amd_erratum(c, amd_div0)) { + pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); + setup_force_cpu_bug(X86_BUG_DIV0); + } } #ifdef CONFIG_X86_32 @@ -1309,3 +1318,13 @@ bool cpu_has_ibpb_brtype_microcode(void) return false; } } + +/* + * Issue a DIV 0/1 insn to clear any division data from previous DIV + * operations. + */ +void noinstr amd_clear_divider(void) +{ + asm volatile(ALTERNATIVE("", "div %2\n\t", X86_BUG_DIV0) + :: "a" (0), "d" (0), "r" (1)); +} diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 4a817d20ce3b..1885326a8f65 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -206,6 +206,8 @@ DEFINE_IDTENTRY(exc_divide_error) { do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, FPE_INTDIV, error_get_trap_addr(regs)); + + amd_clear_divider(); } DEFINE_IDTENTRY(exc_overflow) -- cgit v1.2.3 From 90e065677e0362a777b9db97ea21d43a39211399 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 Jul 2023 11:14:05 -0400 Subject: drm/amdgpu: fix possible UAF in amdgpu_cs_pass1() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the gang_size check is outside of chunk parsing loop, we need to reset i before we free the chunk data. Suggested by Ye Zhang (@VAR10CK) of Baidu Security. Reviewed-by: Guchun Chen Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 040f4cb6ab2d..fb78a8f47587 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -295,7 +295,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, if (!p->gang_size) { ret = -EINVAL; - goto free_partial_kdata; + goto free_all_kdata; } for (i = 0; i < p->gang_size; ++i) { -- cgit v1.2.3 From 3bb575572bf498a9d39e9d1ca5c06cc3152928a1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 28 Jul 2023 17:04:01 -0500 Subject: drm/amd/display: Fix a regression on Polaris cards DCE products don't define a `remove_stream_from_ctx` like DCN ones do. This means that when compute_mst_dsc_configs_for_state() is called it always returns -EINVAL which causes MST to fail to setup. Cc: stable@vger.kernel.org # 6.4.y Cc: Harry Wentland Reported-by: Klaus.Kusche@computerix.info Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/2671 Fixes: efa4c4df864e ("drm/amd/display: call remove_stream_from_ctx from res_pool funcs") Signed-off-by: Mario Limonciello Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 9bc86deac9e8..b885c39bd16b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1320,7 +1320,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, if (computed_streams[i]) continue; - if (!res_pool->funcs->remove_stream_from_ctx || + if (res_pool->funcs->remove_stream_from_ctx && res_pool->funcs->remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK) return -EINVAL; -- cgit v1.2.3 From 2e91e731f24817bc55f9c9acc95a8939c4077b05 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 Jul 2023 16:53:49 -0400 Subject: drm/amdgpu/gfx11: only enable CP GFX shadowing on SR-IOV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is only required for SR-IOV world switches, but it adds additional latency leading to reduced performance in some benchmarks. Disable for now on bare metal. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 3a7af59e83ca..0451533ddde4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -471,8 +471,12 @@ static void gfx_v11_0_check_fw_cp_gfx_shadow(struct amdgpu_device *adev) case IP_VERSION(11, 0, 3): if ((adev->gfx.me_fw_version >= 1505) && (adev->gfx.pfp_fw_version >= 1600) && - (adev->gfx.mec_fw_version >= 512)) - adev->gfx.cp_gfx_shadow = true; + (adev->gfx.mec_fw_version >= 512)) { + if (amdgpu_sriov_vf(adev)) + adev->gfx.cp_gfx_shadow = true; + else + adev->gfx.cp_gfx_shadow = false; + } break; default: adev->gfx.cp_gfx_shadow = false; -- cgit v1.2.3 From a6dea2d64ff92851e68cd4e20a35f6534286e016 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 Jul 2023 11:45:53 -0400 Subject: drm/amdkfd: ignore crat by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are dropping the IOMMUv2 path, so no need to enable this. It's often buggy on consumer platforms anyway. Reviewed-by: Felix Kuehling Acked-by: Christian König Tested-by: Mike Lothian Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 49f40d9f16e8..f5a6f562e2a8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1543,11 +1543,7 @@ static bool kfd_ignore_crat(void) if (ignore_crat) return true; -#ifndef KFD_SUPPORT_IOMMU_V2 ret = true; -#else - ret = false; -#endif return ret; } -- cgit v1.2.3 From 616f92d188ee7142a95a52068efdbea82645f859 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 Jul 2023 11:34:59 -0400 Subject: drm/amdkfd: disable IOMMUv2 support for KV/CZ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dGPU path instead. There were a lot of platform issues with IOMMU in general on these chips due to windows not enabling IOMMU at the time. The dGPU path has been used for a long time with newer APUs and works fine. This also paves the way to simplify the driver significantly. v2: use the dGPU queue manager functions Reviewed-by: Felix Kuehling Acked-by: Christian König Tested-by: Mike Lothian Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 6 ------ drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 0b3dc754e06b..7ae44d68ddc9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -233,10 +233,6 @@ static void kfd_device_info_init(struct kfd_dev *kfd, asic_type != CHIP_TONGA) kfd->device_info.supports_cwsr = true; - if (asic_type == CHIP_KAVERI || - asic_type == CHIP_CARRIZO) - kfd->device_info.needs_iommu_device = true; - if (asic_type != CHIP_HAWAII && !vf) kfd->device_info.needs_pci_atomics = true; } @@ -249,7 +245,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) uint32_t gfx_target_version = 0; switch (adev->asic_type) { -#ifdef KFD_SUPPORT_IOMMU_V2 #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_KAVERI: gfx_target_version = 70000; @@ -262,7 +257,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) if (!vf) f2g = &gfx_v8_kfd2kgd; break; -#endif #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_HAWAII: gfx_target_version = 70001; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 2df153828ff4..01192f5abe46 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2538,18 +2538,12 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) } switch (dev->adev->asic_type) { - case CHIP_CARRIZO: - device_queue_manager_init_vi(&dqm->asic_ops); - break; - case CHIP_KAVERI: - device_queue_manager_init_cik(&dqm->asic_ops); - break; - case CHIP_HAWAII: device_queue_manager_init_cik_hawaii(&dqm->asic_ops); break; + case CHIP_CARRIZO: case CHIP_TONGA: case CHIP_FIJI: case CHIP_POLARIS10: -- cgit v1.2.3 From 091ae5473f96ced844af6ba39b94757359b12348 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 Jul 2023 11:38:02 -0400 Subject: drm/amdkfd: disable IOMMUv2 support for Raven MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dGPU path instead. There were a lot of platform issues with IOMMU in general on these chips due to windows not enabling IOMMU at the time. The dGPU path has been used for a long time with newer APUs and works fine. This also paves the way to simplify the driver significantly. Reviewed-by: Felix Kuehling Acked-by: Christian König Tested-by: Mike Lothian Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 7ae44d68ddc9..a53e0757fe64 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -194,11 +194,6 @@ static void kfd_device_info_init(struct kfd_dev *kfd, kfd_device_info_set_event_interrupt_class(kfd); - /* Raven */ - if (gc_version == IP_VERSION(9, 1, 0) || - gc_version == IP_VERSION(9, 2, 2)) - kfd->device_info.needs_iommu_device = true; - if (gc_version < IP_VERSION(11, 0, 0)) { /* Navi2x+, Navi1x+ */ if (gc_version == IP_VERSION(10, 3, 6)) @@ -292,7 +287,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) gfx_target_version = 90000; f2g = &gfx_v9_kfd2kgd; break; -#ifdef KFD_SUPPORT_IOMMU_V2 /* Raven */ case IP_VERSION(9, 1, 0): case IP_VERSION(9, 2, 2): @@ -300,7 +294,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) if (!vf) f2g = &gfx_v9_kfd2kgd; break; -#endif /* Vega12 */ case IP_VERSION(9, 2, 1): gfx_target_version = 90004; -- cgit v1.2.3 From 22883973244b1caaa26f9c6171a41ba843c8d4bd Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 9 Aug 2023 17:46:00 +0300 Subject: mm: Fix access_remote_vm() regression on tagged addresses GDB uses /proc/PID/mem to access memory of the target process. GDB doesn't untag addresses manually, but relies on kernel to do the right thing. mem_rw() of procfs uses access_remote_vm() to get data from the target process. It worked fine until recent changes in __access_remote_vm() that now checks if there's VMA at target address using raw address. Untag the address before looking up the VMA. Signed-off-by: Kirill A. Shutemov Reported-by: Christina Schimpe Fixes: eee9c708cc89 ("gup: avoid stack expansion warning for known-good case") Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds --- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/memory.c b/mm/memory.c index 603b2f419948..1ec1ef3418bf 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -5705,6 +5705,9 @@ int __access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, if (mmap_read_lock_killable(mm)) return 0; + /* Untag the address before looking up the VMA */ + addr = untagged_addr_remote(mm, addr); + /* Avoid triggering the temporary warning in __get_user_pages */ if (!vma_lookup(mm, addr) && !expand_stack(mm, addr)) return 0; -- cgit v1.2.3 From cacc6e22932f373a91d7be55a9b992dc77f4c59b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 7 Aug 2023 23:12:29 -0500 Subject: tpm: Add a helper for checking hwrng enabled The same checks are repeated in three places to decide whether to use hwrng. Consolidate these into a helper. Also this fixes a case that one of them was missing a check in the cleanup path. Fixes: 554b841d4703 ("tpm: Disable RNG for all AMD fTPMs") Signed-off-by: Mario Limonciello Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm-chip.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e904aae9771b..ea6b4013bc38 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -521,10 +521,20 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) return tpm_get_random(chip, data, max); } +static bool tpm_is_hwrng_enabled(struct tpm_chip *chip) +{ + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + return false; + if (tpm_is_firmware_upgrade(chip)) + return false; + if (chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) + return false; + return true; +} + static int tpm_add_hwrng(struct tpm_chip *chip) { - if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) || - chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) + if (!tpm_is_hwrng_enabled(chip)) return 0; snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), @@ -629,7 +639,7 @@ int tpm_chip_register(struct tpm_chip *chip) return 0; out_hwrng: - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) + if (tpm_is_hwrng_enabled(chip)) hwrng_unregister(&chip->hwrng); out_ppi: tpm_bios_log_teardown(chip); @@ -654,8 +664,7 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) && - !(chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED)) + if (tpm_is_hwrng_enabled(chip)) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) -- cgit v1.2.3 From 6ccbd7fd474674654019a20177c943359469103a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 29 Jul 2023 16:42:23 +0900 Subject: alpha: remove __init annotation from exported page_is_ram() EXPORT_SYMBOL and __init is a bad combination because the .init.text section is freed up after the initialization. Commit c5a130325f13 ("ACPI/APEI: Add parameter check before error injection") exported page_is_ram(), hence the __init annotation should be removed. This fixes the modpost warning in ARCH=alpha builds: WARNING: modpost: vmlinux: page_is_ram: EXPORT_SYMBOL used for init symbol. Remove __init or EXPORT_SYMBOL. Fixes: c5a130325f13 ("ACPI/APEI: Add parameter check before error injection") Signed-off-by: Masahiro Yamada Reviewed-by: Randy Dunlap --- arch/alpha/kernel/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index b650ff1cb022..3d7473531ab1 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -385,8 +385,7 @@ setup_memory(void *kernel_end) #endif /* CONFIG_BLK_DEV_INITRD */ } -int __init -page_is_ram(unsigned long pfn) +int page_is_ram(unsigned long pfn) { struct memclust_struct * cluster; struct memdesc_struct * memdesc; -- cgit v1.2.3 From 2d331a6ac4815e2e2fe5f2d80d908566e57797cc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 9 Aug 2023 10:55:23 +0200 Subject: ACPI: resource: revert "Remove "Zen" specific match and quirks" Commit a9c4a912b7dc ("ACPI: resource: Remove "Zen" specific match and quirks") is causing keyboard problems for quite a log of AMD based laptop users, leading to many bug reports. Revert this change for now, until we can come up with a better fix for the PS/2 IRQ trigger-type/polarity problems on some x86 laptops. Fixes: a9c4a912b7dc ("ACPI: resource: Remove "Zen" specific match and quirks") Link: https://bugzilla.redhat.com/show_bug.cgi?id=2228891 Link: https://bugzilla.redhat.com/show_bug.cgi?id=2229165 Link: https://bugzilla.redhat.com/show_bug.cgi?id=2229317 Link: https://bugzilla.kernel.org/show_bug.cgi?id=217718 Link: https://bugzilla.kernel.org/show_bug.cgi?id=217726 Link: https://bugzilla.kernel.org/show_bug.cgi?id=217731 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 1dd8d5aebf67..0800a9d77558 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -470,6 +470,52 @@ static const struct dmi_system_id asus_laptop[] = { { } }; +static const struct dmi_system_id lenovo_laptop[] = { + { + .ident = "LENOVO IdeaPad Flex 5 14ALC7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82R9"), + }, + }, + { + .ident = "LENOVO IdeaPad Flex 5 16ALC7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82RA"), + }, + }, + { } +}; + +static const struct dmi_system_id tongfang_gm_rg[] = { + { + .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), + }, + }, + { } +}; + +static const struct dmi_system_id maingear_laptop[] = { + { + .ident = "MAINGEAR Vector Pro 2 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), + } + }, + { + .ident = "MAINGEAR Vector Pro 2 17", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"), + }, + }, + { } +}; + static const struct dmi_system_id lg_laptop[] = { { .ident = "LG Electronics 17U70P", @@ -493,6 +539,10 @@ struct irq_override_cmp { static const struct irq_override_cmp override_table[] = { { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, + { lenovo_laptop, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, + { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, + { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, + { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, }; @@ -512,6 +562,16 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, return entry->override; } +#ifdef CONFIG_X86 + /* + * IRQ override isn't needed on modern AMD Zen systems and + * this override breaks active low IRQs on AMD Ryzen 6000 and + * newer systems. Skip it. + */ + if (boot_cpu_has(X86_FEATURE_ZEN)) + return false; +#endif + return true; } -- cgit v1.2.3 From 9728ac221160c5ea111879125a7694bb81364720 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 9 Aug 2023 10:55:24 +0200 Subject: ACPI: resource: Always use MADT override IRQ settings for all legacy non i8042 IRQs All the cases, were the DSDT IRQ settings should be used instead of the MADT override, are for IRQ 1 or 12, the PS/2 kbd resp. mouse IRQs. Simplify things by always honering the override for other legacy IRQs (for non DMI quirked cases). This allows removing the DMI quirks to honor the override for some non i8042 IRQs on some AMD ZEN based Lenovo models. Fixes: a9c4a912b7dc ("ACPI: resource: Remove "Zen" specific match and quirks") Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 0800a9d77558..380cda1e86f4 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -470,24 +470,6 @@ static const struct dmi_system_id asus_laptop[] = { { } }; -static const struct dmi_system_id lenovo_laptop[] = { - { - .ident = "LENOVO IdeaPad Flex 5 14ALC7", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "82R9"), - }, - }, - { - .ident = "LENOVO IdeaPad Flex 5 16ALC7", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "82RA"), - }, - }, - { } -}; - static const struct dmi_system_id tongfang_gm_rg[] = { { .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", @@ -539,8 +521,6 @@ struct irq_override_cmp { static const struct irq_override_cmp override_table[] = { { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, - { lenovo_laptop, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, - { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, @@ -563,6 +543,14 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, } #ifdef CONFIG_X86 + /* + * Always use the MADT override info, except for the i8042 PS/2 ctrl + * IRQs (1 and 12). For these the DSDT IRQ settings should sometimes + * be used otherwise PS/2 keyboards / mice will not work. + */ + if (gsi != 1 && gsi != 12) + return true; + /* * IRQ override isn't needed on modern AMD Zen systems and * this override breaks active low IRQs on AMD Ryzen 6000 and -- cgit v1.2.3 From c6a1fd910d1bf8a0e3db7aebb229e3c81bc305c4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 9 Aug 2023 10:55:25 +0200 Subject: ACPI: resource: Honor MADT INT_SRC_OVR settings for IRQ1 on AMD Zen On AMD Zen acpi_dev_irq_override() by default prefers the DSDT IRQ 1 settings over the MADT settings. This causes the keyboard to malfunction on some laptop models (see Links), all models from the Links have an INT_SRC_OVR MADT entry for IRQ 1. Fixes: a9c4a912b7dc ("ACPI: resource: Remove "Zen" specific match and quirks") Link: https://bugzilla.kernel.org/show_bug.cgi?id=217336 Link: https://bugzilla.kernel.org/show_bug.cgi?id=217394 Link: https://bugzilla.kernel.org/show_bug.cgi?id=217406 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- arch/x86/include/asm/acpi.h | 2 ++ arch/x86/kernel/acpi/boot.c | 4 ++++ drivers/acpi/resource.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 8eb74cf386db..2888c0ee4df0 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI_APEI # include @@ -31,6 +32,7 @@ extern int acpi_skip_timer_override; extern int acpi_use_timer_override; extern int acpi_fix_pin2_polarity; extern int acpi_disable_cmcff; +extern bool acpi_int_src_ovr[NR_IRQS_LEGACY]; extern u8 acpi_sci_flags; extern u32 acpi_sci_override_gsi; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 21b542a6866c..53369c57751e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -52,6 +52,7 @@ int acpi_lapic; int acpi_ioapic; int acpi_strict; int acpi_disable_cmcff; +bool acpi_int_src_ovr[NR_IRQS_LEGACY]; /* ACPI SCI override configuration */ u8 acpi_sci_flags __initdata; @@ -588,6 +589,9 @@ acpi_parse_int_src_ovr(union acpi_subtable_headers * header, acpi_table_print_madt_entry(&header->common); + if (intsrc->source_irq < NR_IRQS_LEGACY) + acpi_int_src_ovr[intsrc->source_irq] = true; + if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) { acpi_sci_ioapic_setup(intsrc->source_irq, intsrc->inti_flags & ACPI_MADT_POLARITY_MASK, diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 380cda1e86f4..8e32dd5776f5 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -551,6 +551,10 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, if (gsi != 1 && gsi != 12) return true; + /* If the override comes from an INT_SRC_OVR MADT entry, honor it. */ + if (acpi_int_src_ovr[gsi]) + return true; + /* * IRQ override isn't needed on modern AMD Zen systems and * this override breaks active low IRQs on AMD Ryzen 6000 and -- cgit v1.2.3 From 5a66d59b5ff537ddae84a1f175c3f8eb1140a562 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 5 Aug 2023 10:10:10 +0200 Subject: platform/x86: msi-ec: Fix the build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The msi-ec driver fails to build for me (gcc 7.5): CC [M] drivers/platform/x86/msi-ec.o drivers/platform/x86/msi-ec.c:72:6: error: initializer element is not constant { SM_ECO_NAME, 0xc2 }, ^~~~~~~~~~~ drivers/platform/x86/msi-ec.c:72:6: note: (near initialization for ‘CONF0.shift_mode.modes[0].name’) drivers/platform/x86/msi-ec.c:73:6: error: initializer element is not constant { SM_COMFORT_NAME, 0xc1 }, ^~~~~~~~~~~~~~~ drivers/platform/x86/msi-ec.c:73:6: note: (near initialization for ‘CONF0.shift_mode.modes[1].name’) drivers/platform/x86/msi-ec.c:74:6: error: initializer element is not constant { SM_SPORT_NAME, 0xc0 }, ^~~~~~~~~~~~~ drivers/platform/x86/msi-ec.c:74:6: note: (near initialization for ‘CONF0.shift_mode.modes[2].name’) (...) Don't try to be smart, just use defines for the constant strings. The compiler will recognize it's the same string and will store it only once in the data section anyway. Signed-off-by: Jean Delvare Fixes: 392cacf2aa10 ("platform/x86: Add new msi-ec driver") Cc: stable@vger.kernel.org Cc: Nikita Kravets Cc: Hans de Goede Cc: Mark Gross Link: https://lore.kernel.org/r/20230805101010.54d49e91@endymion.delvare Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/msi-ec.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c index ff93986e3d35..f26a3121092f 100644 --- a/drivers/platform/x86/msi-ec.c +++ b/drivers/platform/x86/msi-ec.c @@ -27,15 +27,15 @@ #include #include -static const char *const SM_ECO_NAME = "eco"; -static const char *const SM_COMFORT_NAME = "comfort"; -static const char *const SM_SPORT_NAME = "sport"; -static const char *const SM_TURBO_NAME = "turbo"; - -static const char *const FM_AUTO_NAME = "auto"; -static const char *const FM_SILENT_NAME = "silent"; -static const char *const FM_BASIC_NAME = "basic"; -static const char *const FM_ADVANCED_NAME = "advanced"; +#define SM_ECO_NAME "eco" +#define SM_COMFORT_NAME "comfort" +#define SM_SPORT_NAME "sport" +#define SM_TURBO_NAME "turbo" + +#define FM_AUTO_NAME "auto" +#define FM_SILENT_NAME "silent" +#define FM_BASIC_NAME "basic" +#define FM_ADVANCED_NAME "advanced" static const char * const ALLOWED_FW_0[] __initconst = { "14C1EMS1.012", -- cgit v1.2.3 From af8a6d281bfb68023fb60f616ec87fe8a875875e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 8 Aug 2023 10:43:59 -0700 Subject: platform/x86: ISST: Reduce noise for missing numa information in logs On platforms with no numa support and with several CPUs, logs have lots of noise for message "Fail to get numa node for CPU:.." Change pr_info() to pr_info_once() as one print is enough to show the issue. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230808174359.50602-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/speed_select_if/isst_if_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c index 1f59ac55c5f7..a95004e3d80b 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c @@ -335,8 +335,8 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn node = dev_to_node(&_pci_dev->dev); if (node == NUMA_NO_NODE) { - pr_info("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n", - cpu, bus_no, dev, fn); + pr_info_once("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n", + cpu, bus_no, dev, fn); continue; } -- cgit v1.2.3 From 1b8b1aa90c9c0e825b181b98b8d9e249dc395470 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 3 Aug 2023 18:16:09 +0300 Subject: x86/mm: Fix VDSO and VVAR placement on 5-level paging machines Yingcong has noticed that on the 5-level paging machine, VDSO and VVAR VMAs are placed above the 47-bit border: 8000001a9000-8000001ad000 r--p 00000000 00:00 0 [vvar] 8000001ad000-8000001af000 r-xp 00000000 00:00 0 [vdso] This might confuse users who are not aware of 5-level paging and expect all userspace addresses to be under the 47-bit border. So far problem has only been triggered with ASLR disabled, although it may also occur with ASLR enabled if the layout is randomized in a just right way. The problem happens due to custom placement for the VMAs in the VDSO code: vdso_addr() tries to place them above the stack and checks the result against TASK_SIZE_MAX, which is wrong. TASK_SIZE_MAX is set to the 56-bit border on 5-level paging machines. Use DEFAULT_MAP_WINDOW instead. Fixes: b569bab78d8d ("x86/mm: Prepare to expose larger address space to userspace") Reported-by: Yingcong Wu Signed-off-by: Kirill A. Shutemov Signed-off-by: Dave Hansen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20230803151609.22141-1-kirill.shutemov%40linux.intel.com --- arch/x86/entry/vdso/vma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index 11a5c68d1218..7645730dc228 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -299,8 +299,8 @@ static unsigned long vdso_addr(unsigned long start, unsigned len) /* Round the lowest possible end address up to a PMD boundary. */ end = (start + len + PMD_SIZE - 1) & PMD_MASK; - if (end >= TASK_SIZE_MAX) - end = TASK_SIZE_MAX; + if (end >= DEFAULT_MAP_WINDOW) + end = DEFAULT_MAP_WINDOW; end -= len; if (end > start) { -- cgit v1.2.3 From 718cb09aaa6fa78cc8124e9517efbc6c92665384 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Tue, 8 Aug 2023 11:35:21 +0200 Subject: vlan: Fix VLAN 0 memory leak The referenced commit intended to fix memleak of VLAN 0 that is implicitly created on devices with NETIF_F_HW_VLAN_CTAG_FILTER feature. However, it doesn't take into account that the feature can be re-set during the netdevice lifetime which will cause memory leak if feature is disabled during the device deletion as illustrated by [0]. Fix the leak by unconditionally deleting VLAN 0 on NETDEV_DOWN event. [0]: > modprobe 8021q > ip l set dev eth2 up > ethtool -K eth2 rx-vlan-filter off > modprobe -r mlx5_ib > modprobe -r mlx5_core > cat /sys/kernel/debug/kmemleak unreferenced object 0xffff888103dcd900 (size 256): comm "ip", pid 1490, jiffies 4294907305 (age 325.364s) hex dump (first 32 bytes): 00 80 5d 03 81 88 ff ff 00 00 00 00 00 00 00 00 ..]............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000899f3bb9>] kmalloc_trace+0x25/0x80 [<000000002889a7a2>] vlan_vid_add+0xa0/0x210 [<000000007177800e>] vlan_device_event+0x374/0x760 [8021q] [<000000009a0716b1>] notifier_call_chain+0x35/0xb0 [<00000000bbf3d162>] __dev_notify_flags+0x58/0xf0 [<0000000053d2b05d>] dev_change_flags+0x4d/0x60 [<00000000982807e9>] do_setlink+0x28d/0x10a0 [<0000000058c1be00>] __rtnl_newlink+0x545/0x980 [<00000000e66c3bd9>] rtnl_newlink+0x44/0x70 [<00000000a2cc5970>] rtnetlink_rcv_msg+0x29c/0x390 [<00000000d307d1e4>] netlink_rcv_skb+0x54/0x100 [<00000000259d16f9>] netlink_unicast+0x1f6/0x2c0 [<000000007ce2afa1>] netlink_sendmsg+0x232/0x4a0 [<00000000f3f4bb39>] sock_sendmsg+0x38/0x60 [<000000002f9c0624>] ____sys_sendmsg+0x1e3/0x200 [<00000000d6ff5520>] ___sys_sendmsg+0x80/0xc0 unreferenced object 0xffff88813354fde0 (size 32): comm "ip", pid 1490, jiffies 4294907305 (age 325.364s) hex dump (first 32 bytes): a0 d9 dc 03 81 88 ff ff a0 d9 dc 03 81 88 ff ff ................ 81 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000899f3bb9>] kmalloc_trace+0x25/0x80 [<000000002da64724>] vlan_vid_add+0xdf/0x210 [<000000007177800e>] vlan_device_event+0x374/0x760 [8021q] [<000000009a0716b1>] notifier_call_chain+0x35/0xb0 [<00000000bbf3d162>] __dev_notify_flags+0x58/0xf0 [<0000000053d2b05d>] dev_change_flags+0x4d/0x60 [<00000000982807e9>] do_setlink+0x28d/0x10a0 [<0000000058c1be00>] __rtnl_newlink+0x545/0x980 [<00000000e66c3bd9>] rtnl_newlink+0x44/0x70 [<00000000a2cc5970>] rtnetlink_rcv_msg+0x29c/0x390 [<00000000d307d1e4>] netlink_rcv_skb+0x54/0x100 [<00000000259d16f9>] netlink_unicast+0x1f6/0x2c0 [<000000007ce2afa1>] netlink_sendmsg+0x232/0x4a0 [<00000000f3f4bb39>] sock_sendmsg+0x38/0x60 [<000000002f9c0624>] ____sys_sendmsg+0x1e3/0x200 [<00000000d6ff5520>] ___sys_sendmsg+0x80/0xc0 Fixes: efc73f4bbc23 ("net: Fix memory leak - vlan_info struct") Reviewed-by: Ido Schimmel Signed-off-by: Vlad Buslov Link: https://lore.kernel.org/r/20230808093521.1468929-1-vladbu@nvidia.com Signed-off-by: Jakub Kicinski --- net/8021q/vlan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e40aa3e3641c..b3662119ddbc 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -384,8 +384,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, dev->name); vlan_vid_add(dev, htons(ETH_P_8021Q), 0); } - if (event == NETDEV_DOWN && - (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) + if (event == NETDEV_DOWN) vlan_vid_del(dev, htons(ETH_P_8021Q), 0); vlan_info = rtnl_dereference(dev->vlan_info); -- cgit v1.2.3 From 913f60cacda73ccac8eead94983e5884c03e04cd Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 10:52:31 +0300 Subject: nexthop: Fix infinite nexthop dump when using maximum nexthop ID A netlink dump callback can return a positive number to signal that more information needs to be dumped or zero to signal that the dump is complete. In the second case, the core netlink code will append the NLMSG_DONE message to the skb in order to indicate to user space that the dump is complete. The nexthop dump callback always returns a positive number if nexthops were filled in the provided skb, even if the dump is complete. This means that a dump will span at least two recvmsg() calls as long as nexthops are present. In the last recvmsg() call the dump callback will not fill in any nexthops because the previous call indicated that the dump should restart from the last dumped nexthop ID plus one. # ip nexthop add id 1 blackhole # strace -e sendto,recvmsg -s 5 ip nexthop sendto(3, [[{nlmsg_len=24, nlmsg_type=RTM_GETNEXTHOP, nlmsg_flags=NLM_F_REQUEST|NLM_F_DUMP, nlmsg_seq=1691394315, nlmsg_pid=0}, {nh_family=AF_UNSPEC, nh_scope=RT_SCOPE_UNIVERSE, nh_protocol=RTPROT_UNSPEC, nh_flags=0}], {nlmsg_len=0, nlmsg_type=0 /* NLMSG_??? */, nlmsg_flags=0, nlmsg_seq=0, nlmsg_pid=0}], 152, 0, NULL, 0) = 152 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 36 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=36, nlmsg_type=RTM_NEWNEXTHOP, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691394315, nlmsg_pid=343}, {nh_family=AF_INET, nh_scope=RT_SCOPE_UNIVERSE, nh_protocol=RTPROT_UNSPEC, nh_flags=0}, [[{nla_len=8, nla_type=NHA_ID}, 1], {nla_len=4, nla_type=NHA_BLACKHOLE}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 36 id 1 blackhole recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 20 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=20, nlmsg_type=NLMSG_DONE, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691394315, nlmsg_pid=343}, 0], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 20 +++ exited with 0 +++ This behavior is both inefficient and buggy. If the last nexthop to be dumped had the maximum ID of 0xffffffff, then the dump will restart from 0 (0xffffffff + 1) and never end: # ip nexthop add id $((2**32-1)) blackhole # ip nexthop id 4294967295 blackhole id 4294967295 blackhole [...] Fix by adjusting the dump callback to return zero when the dump is complete. After the fix only one recvmsg() call is made and the NLMSG_DONE message is appended to the RTM_NEWNEXTHOP response: # ip nexthop add id $((2**32-1)) blackhole # strace -e sendto,recvmsg -s 5 ip nexthop sendto(3, [[{nlmsg_len=24, nlmsg_type=RTM_GETNEXTHOP, nlmsg_flags=NLM_F_REQUEST|NLM_F_DUMP, nlmsg_seq=1691394080, nlmsg_pid=0}, {nh_family=AF_UNSPEC, nh_scope=RT_SCOPE_UNIVERSE, nh_protocol=RTPROT_UNSPEC, nh_flags=0}], {nlmsg_len=0, nlmsg_type=0 /* NLMSG_??? */, nlmsg_flags=0, nlmsg_seq=0, nlmsg_pid=0}], 152, 0, NULL, 0) = 152 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 56 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[[{nlmsg_len=36, nlmsg_type=RTM_NEWNEXTHOP, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691394080, nlmsg_pid=342}, {nh_family=AF_INET, nh_scope=RT_SCOPE_UNIVERSE, nh_protocol=RTPROT_UNSPEC, nh_flags=0}, [[{nla_len=8, nla_type=NHA_ID}, 4294967295], {nla_len=4, nla_type=NHA_BLACKHOLE}]], [{nlmsg_len=20, nlmsg_type=NLMSG_DONE, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691394080, nlmsg_pid=342}, 0]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 56 id 4294967295 blackhole +++ exited with 0 +++ Note that if the NLMSG_DONE message cannot be appended because of size limitations, then another recvmsg() will be needed, but the core netlink code will not invoke the dump callback and simply reply with a NLMSG_DONE message since it knows that the callback previously returned zero. Add a test that fails before the fix: # ./fib_nexthops.sh -t basic [...] TEST: Maximum nexthop ID dump [FAIL] [...] And passes after it: # ./fib_nexthops.sh -t basic [...] TEST: Maximum nexthop ID dump [ OK ] [...] Fixes: ab84be7e54fc ("net: Initial nexthop code") Reported-by: Petr Machata Closes: https://lore.kernel.org/netdev/87sf91enuf.fsf@nvidia.com/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230808075233.3337922-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 6 +----- tools/testing/selftests/net/fib_nexthops.sh | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index f95142e56da0..179e50d8fe07 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3221,13 +3221,9 @@ static int rtm_dump_nexthop(struct sk_buff *skb, struct netlink_callback *cb) &rtm_dump_nexthop_cb, &filter); if (err < 0) { if (likely(skb->len)) - goto out; - goto out_err; + err = skb->len; } -out: - err = skb->len; -out_err: cb->seq = net->nexthop.seq; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); return err; diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh index 0f5e88c8f4ff..10aa059b9f06 100755 --- a/tools/testing/selftests/net/fib_nexthops.sh +++ b/tools/testing/selftests/net/fib_nexthops.sh @@ -1981,6 +1981,11 @@ basic() run_cmd "$IP link set dev lo up" + # Dump should not loop endlessly when maximum nexthop ID is configured. + run_cmd "$IP nexthop add id $((2**32-1)) blackhole" + run_cmd "timeout 5 $IP nexthop" + log_test $? 0 "Maximum nexthop ID dump" + # # groups # -- cgit v1.2.3 From f10d3d9df49d9e6ee244fda6ca264f901a9c5d85 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 10:52:32 +0300 Subject: nexthop: Make nexthop bucket dump more efficient rtm_dump_nexthop_bucket_nh() is used to dump nexthop buckets belonging to a specific resilient nexthop group. The function returns a positive return code (the skb length) upon both success and failure. The above behavior is problematic. When a complete nexthop bucket dump is requested, the function that walks the different nexthops treats the non-zero return code as an error. This causes buckets belonging to different resilient nexthop groups to be dumped using different buffers even if they can all fit in the same buffer: # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip nexthop add id 10 group 1 type resilient buckets 1 # ip nexthop add id 20 group 1 type resilient buckets 1 # strace -e recvmsg -s 0 ip nexthop bucket [...] recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[...], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 64 id 10 index 0 idle_time 10.27 nhid 1 [...] recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[...], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 64 id 20 index 0 idle_time 6.44 nhid 1 [...] Fix by only returning a non-zero return code when an error occurred and restarting the dump from the bucket index we failed to fill in. This allows buckets belonging to different resilient nexthop groups to be dumped using the same buffer: # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip nexthop add id 10 group 1 type resilient buckets 1 # ip nexthop add id 20 group 1 type resilient buckets 1 # strace -e recvmsg -s 0 ip nexthop bucket [...] recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[...], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 128 id 10 index 0 idle_time 30.21 nhid 1 id 20 index 0 idle_time 26.7 nhid 1 [...] While this change is more of a performance improvement change than an actual bug fix, it is a prerequisite for a subsequent patch that does fix a bug. Fixes: 8a1bbabb034d ("nexthop: Add netlink handlers for bucket dump") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230808075233.3337922-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 179e50d8fe07..f365a4f63899 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3363,25 +3363,19 @@ static int rtm_dump_nexthop_bucket_nh(struct sk_buff *skb, dd->filter.res_bucket_nh_id != nhge->nh->id) continue; + dd->ctx->bucket_index = bucket_index; err = nh_fill_res_bucket(skb, nh, bucket, bucket_index, RTM_NEWNEXTHOPBUCKET, portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->extack); - if (err < 0) { - if (likely(skb->len)) - goto out; - goto out_err; - } + if (err) + return err; } dd->ctx->done_nh_idx = dd->ctx->nh.idx + 1; - bucket_index = 0; + dd->ctx->bucket_index = 0; -out: - err = skb->len; -out_err: - dd->ctx->bucket_index = bucket_index; - return err; + return 0; } static int rtm_dump_nexthop_bucket_cb(struct sk_buff *skb, -- cgit v1.2.3 From 8743aeff5bc4dcb5b87b43765f48d5ac3ad7dd9f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 10:52:33 +0300 Subject: nexthop: Fix infinite nexthop bucket dump when using maximum nexthop ID A netlink dump callback can return a positive number to signal that more information needs to be dumped or zero to signal that the dump is complete. In the second case, the core netlink code will append the NLMSG_DONE message to the skb in order to indicate to user space that the dump is complete. The nexthop bucket dump callback always returns a positive number if nexthop buckets were filled in the provided skb, even if the dump is complete. This means that a dump will span at least two recvmsg() calls as long as nexthop buckets are present. In the last recvmsg() call the dump callback will not fill in any nexthop buckets because the previous call indicated that the dump should restart from the last dumped nexthop ID plus one. # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip nexthop add id 10 group 1 type resilient buckets 2 # strace -e sendto,recvmsg -s 5 ip nexthop bucket sendto(3, [[{nlmsg_len=24, nlmsg_type=RTM_GETNEXTHOPBUCKET, nlmsg_flags=NLM_F_REQUEST|NLM_F_DUMP, nlmsg_seq=1691396980, nlmsg_pid=0}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}], {nlmsg_len=0, nlmsg_type=0 /* NLMSG_??? */, nlmsg_flags=0, nlmsg_seq=0, nlmsg_pid=0}], 152, 0, NULL, 0) = 152 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 128 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[[{nlmsg_len=64, nlmsg_type=RTM_NEWNEXTHOPBUCKET, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396980, nlmsg_pid=347}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}], [{nlmsg_len=64, nlmsg_type=RTM_NEWNEXTHOPBUCKET, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396980, nlmsg_pid=347}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 128 id 10 index 0 idle_time 6.66 nhid 1 id 10 index 1 idle_time 6.66 nhid 1 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 20 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=20, nlmsg_type=NLMSG_DONE, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396980, nlmsg_pid=347}, 0], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 20 +++ exited with 0 +++ This behavior is both inefficient and buggy. If the last nexthop to be dumped had the maximum ID of 0xffffffff, then the dump will restart from 0 (0xffffffff + 1) and never end: # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip nexthop add id $((2**32-1)) group 1 type resilient buckets 2 # ip nexthop bucket id 4294967295 index 0 idle_time 5.55 nhid 1 id 4294967295 index 1 idle_time 5.55 nhid 1 id 4294967295 index 0 idle_time 5.55 nhid 1 id 4294967295 index 1 idle_time 5.55 nhid 1 [...] Fix by adjusting the dump callback to return zero when the dump is complete. After the fix only one recvmsg() call is made and the NLMSG_DONE message is appended to the RTM_NEWNEXTHOPBUCKET responses: # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip nexthop add id $((2**32-1)) group 1 type resilient buckets 2 # strace -e sendto,recvmsg -s 5 ip nexthop bucket sendto(3, [[{nlmsg_len=24, nlmsg_type=RTM_GETNEXTHOPBUCKET, nlmsg_flags=NLM_F_REQUEST|NLM_F_DUMP, nlmsg_seq=1691396737, nlmsg_pid=0}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}], {nlmsg_len=0, nlmsg_type=0 /* NLMSG_??? */, nlmsg_flags=0, nlmsg_seq=0, nlmsg_pid=0}], 152, 0, NULL, 0) = 152 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 148 recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[[{nlmsg_len=64, nlmsg_type=RTM_NEWNEXTHOPBUCKET, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396737, nlmsg_pid=350}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}], [{nlmsg_len=64, nlmsg_type=RTM_NEWNEXTHOPBUCKET, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396737, nlmsg_pid=350}, {family=AF_UNSPEC, data="\x00\x00\x00\x00\x00"...}], [{nlmsg_len=20, nlmsg_type=NLMSG_DONE, nlmsg_flags=NLM_F_MULTI, nlmsg_seq=1691396737, nlmsg_pid=350}, 0]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 148 id 4294967295 index 0 idle_time 6.61 nhid 1 id 4294967295 index 1 idle_time 6.61 nhid 1 +++ exited with 0 +++ Note that if the NLMSG_DONE message cannot be appended because of size limitations, then another recvmsg() will be needed, but the core netlink code will not invoke the dump callback and simply reply with a NLMSG_DONE message since it knows that the callback previously returned zero. Add a test that fails before the fix: # ./fib_nexthops.sh -t basic_res [...] TEST: Maximum nexthop ID dump [FAIL] [...] And passes after it: # ./fib_nexthops.sh -t basic_res [...] TEST: Maximum nexthop ID dump [ OK ] [...] Fixes: 8a1bbabb034d ("nexthop: Add netlink handlers for bucket dump") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230808075233.3337922-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 6 +----- tools/testing/selftests/net/fib_nexthops.sh | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index f365a4f63899..be5498f5dd31 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3424,13 +3424,9 @@ static int rtm_dump_nexthop_bucket(struct sk_buff *skb, if (err < 0) { if (likely(skb->len)) - goto out; - goto out_err; + err = skb->len; } -out: - err = skb->len; -out_err: cb->seq = net->nexthop.seq; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); return err; diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh index 10aa059b9f06..df8d90b51867 100755 --- a/tools/testing/selftests/net/fib_nexthops.sh +++ b/tools/testing/selftests/net/fib_nexthops.sh @@ -2206,6 +2206,11 @@ basic_res() run_cmd "$IP nexthop bucket list fdb" log_test $? 255 "Dump all nexthop buckets with invalid 'fdb' keyword" + # Dump should not loop endlessly when maximum nexthop ID is configured. + run_cmd "$IP nexthop add id $((2**32-1)) group 1/2 type resilient buckets 4" + run_cmd "timeout 5 $IP nexthop bucket" + log_test $? 0 "Maximum nexthop ID dump" + # # resilient nexthop buckets get requests # -- cgit v1.2.3 From 8a70ed9520c5fafaac91053cacdd44625c39e188 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 8 Aug 2023 08:49:23 +0000 Subject: tcp: add missing family to tcp_set_ca_state() tracepoint Before this code is copied, add the missing family, as we did in commit 3dd344ea84e1 ("net: tracepoint: exposing sk_family in all tcp:tracepoints") Fixes: 15fcdf6ae116 ("tcp: Add tracepoint for tcp_set_ca_state") Signed-off-by: Eric Dumazet Cc: Ping Gan Cc: Manjusaka Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230808084923.2239142-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/trace/events/tcp.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h index bf06db8d2046..7b1ddffa3dfc 100644 --- a/include/trace/events/tcp.h +++ b/include/trace/events/tcp.h @@ -381,6 +381,7 @@ TRACE_EVENT(tcp_cong_state_set, __field(const void *, skaddr) __field(__u16, sport) __field(__u16, dport) + __field(__u16, family) __array(__u8, saddr, 4) __array(__u8, daddr, 4) __array(__u8, saddr_v6, 16) @@ -396,6 +397,7 @@ TRACE_EVENT(tcp_cong_state_set, __entry->sport = ntohs(inet->inet_sport); __entry->dport = ntohs(inet->inet_dport); + __entry->family = sk->sk_family; p32 = (__be32 *) __entry->saddr; *p32 = inet->inet_saddr; @@ -409,7 +411,8 @@ TRACE_EVENT(tcp_cong_state_set, __entry->cong_state = ca_state; ), - TP_printk("sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c cong_state=%u", + TP_printk("family=%s sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c cong_state=%u", + show_family_name(__entry->family), __entry->sport, __entry->dport, __entry->saddr, __entry->daddr, __entry->saddr_v6, __entry->daddr_v6, -- cgit v1.2.3 From d72c83b1e4b4a36a38269c77a85ff52f95eb0d08 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:47 +0300 Subject: selftests: forwarding: Skip test when no interfaces are specified As explained in [1], the forwarding selftests are meant to be run with either physical loopbacks or veth pairs. The interfaces are expected to be specified in a user-provided forwarding.config file or as command line arguments. By default, this file is not present and the tests fail: # make -C tools/testing/selftests TARGETS=net/forwarding run_tests [...] TAP version 13 1..102 # timeout set to 45 # selftests: net/forwarding: bridge_igmp.sh # Command line is not complete. Try option "help" # Failed to create netif not ok 1 selftests: net/forwarding: bridge_igmp.sh # exit=1 [...] Fix by skipping a test if interfaces are not provided either via the configuration file or command line arguments. # make -C tools/testing/selftests TARGETS=net/forwarding run_tests [...] TAP version 13 1..102 # timeout set to 45 # selftests: net/forwarding: bridge_igmp.sh # SKIP: Cannot create interface. Name not specified ok 1 selftests: net/forwarding: bridge_igmp.sh # SKIP [1] tools/testing/selftests/net/forwarding/README Fixes: 81573b18f26d ("selftests/net/forwarding: add Makefile to install tests") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/856d454e-f83c-20cf-e166-6dc06cbc1543@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/lib.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 9ddb68dd6a08..975fc5168c63 100755 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -225,6 +225,11 @@ create_netif_veth() for ((i = 1; i <= NUM_NETIFS; ++i)); do local j=$((i+1)) + if [ -z ${NETIFS[p$i]} ]; then + echo "SKIP: Cannot create interface. Name not specified" + exit $ksft_skip + fi + ip link show dev ${NETIFS[p$i]} &> /dev/null if [[ $? -ne 0 ]]; then ip link add ${NETIFS[p$i]} type veth \ -- cgit v1.2.3 From 0529883ad102f6c04e19fb7018f31e1bda575bbe Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:48 +0300 Subject: selftests: forwarding: Switch off timeout The default timeout for selftests is 45 seconds, but it is not enough for forwarding selftests which can takes minutes to finish depending on the number of tests cases: # make -C tools/testing/selftests TARGETS=net/forwarding run_tests TAP version 13 1..102 # timeout set to 45 # selftests: net/forwarding: bridge_igmp.sh # TEST: IGMPv2 report 239.10.10.10 [ OK ] # TEST: IGMPv2 leave 239.10.10.10 [ OK ] # TEST: IGMPv3 report 239.10.10.10 is_include [ OK ] # TEST: IGMPv3 report 239.10.10.10 include -> allow [ OK ] # not ok 1 selftests: net/forwarding: bridge_igmp.sh # TIMEOUT 45 seconds Fix by switching off the timeout and setting it to 0. A similar change was done for BPF selftests in commit 6fc5916cc256 ("selftests: bpf: Switch off timeout"). Fixes: 81573b18f26d ("selftests/net/forwarding: add Makefile to install tests") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/8d149f8c-818e-d141-a0ce-a6bae606bc22@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/settings | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/testing/selftests/net/forwarding/settings diff --git a/tools/testing/selftests/net/forwarding/settings b/tools/testing/selftests/net/forwarding/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/net/forwarding/settings @@ -0,0 +1 @@ +timeout=0 -- cgit v1.2.3 From ab2eda04e2c2116910b9d77ccc82e727efa71d49 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:49 +0300 Subject: selftests: forwarding: bridge_mdb: Check iproute2 version The selftest relies on iproute2 changes present in version 6.3, but the test does not check for it, resulting in error: # ./bridge_mdb.sh INFO: # Host entries configuration tests TEST: Common host entries configuration tests (IPv4) [FAIL] Managed to add IPv4 host entry with a filter mode TEST: Common host entries configuration tests (IPv6) [FAIL] Managed to add IPv6 host entry with a filter mode TEST: Common host entries configuration tests (L2) [FAIL] Managed to add L2 host entry with a filter mode INFO: # Port group entries configuration tests - (*, G) Command "replace" is unknown, try "bridge mdb help". [...] Fix by skipping the test if iproute2 is too old. Fixes: b6d00da08610 ("selftests: forwarding: Add bridge MDB test") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/6b04b2ba-2372-6f6b-3ac8-b7cba1cfae83@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/bridge_mdb.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh index ae3f9462a2b6..6f830b5f03c9 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh @@ -1206,6 +1206,11 @@ ctrl_test() ctrl_mldv2_is_in_test } +if ! bridge mdb help 2>&1 | grep -q "replace"; then + echo "SKIP: iproute2 too old, missing bridge mdb replace support" + exit $ksft_skip +fi + trap cleanup EXIT setup_prepare -- cgit v1.2.3 From 6bdf3d9765f4e0eebfd919e70acc65bce5daa9b9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:50 +0300 Subject: selftests: forwarding: bridge_mdb_max: Check iproute2 version The selftest relies on iproute2 changes present in version 6.3, but the test does not check for it, resulting in errors: # ./bridge_mdb_max.sh INFO: 802.1d tests TEST: cfg4: port: ngroups reporting [FAIL] Number of groups was null, now is null, but 5 expected TEST: ctl4: port: ngroups reporting [FAIL] Number of groups was null, now is null, but 5 expected TEST: cfg6: port: ngroups reporting [FAIL] Number of groups was null, now is null, but 5 expected [...] Fix by skipping the test if iproute2 is too old. Fixes: 3446dcd7df05 ("selftests: forwarding: bridge_mdb_max: Add a new selftest") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/6b04b2ba-2372-6f6b-3ac8-b7cba1cfae83@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-5-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/bridge_mdb_max.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh b/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh index ae255b662ba3..fa762b716288 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh @@ -1328,6 +1328,11 @@ test_8021qvs() switch_destroy } +if ! bridge link help 2>&1 | grep -q "mcast_max_groups"; then + echo "SKIP: iproute2 too old, missing bridge \"mcast_max_groups\" support" + exit $ksft_skip +fi + trap cleanup EXIT setup_prepare -- cgit v1.2.3 From 38f7c44d6e760a8513557e27340d61b820c91b8f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:51 +0300 Subject: selftests: forwarding: Set default IPv6 traceroute utility The test uses the 'TROUTE6' environment variable to encode the name of the IPv6 traceroute utility. By default (without a configuration file), this variable is not set, resulting in failures: # ./ip6_forward_instats_vrf.sh TEST: ping6 [ OK ] TEST: Ip6InTooBigErrors [ OK ] TEST: Ip6InHdrErrors [FAIL] TEST: Ip6InAddrErrors [ OK ] TEST: Ip6InDiscards [ OK ] Fix by setting a default utility name and skip the test if the utility is not present. Fixes: 0857d6f8c759 ("ipv6: When forwarding count rx stats on the orig netdev") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-6-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/ip6_forward_instats_vrf.sh | 2 ++ tools/testing/selftests/net/forwarding/lib.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/ip6_forward_instats_vrf.sh b/tools/testing/selftests/net/forwarding/ip6_forward_instats_vrf.sh index 9f5b3e2e5e95..49fa94b53a1c 100755 --- a/tools/testing/selftests/net/forwarding/ip6_forward_instats_vrf.sh +++ b/tools/testing/selftests/net/forwarding/ip6_forward_instats_vrf.sh @@ -14,6 +14,8 @@ ALL_TESTS=" NUM_NETIFS=4 source lib.sh +require_command $TROUTE6 + h1_create() { simple_if_init $h1 2001:1:1::2/64 diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 975fc5168c63..40a8c1541b7f 100755 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -30,6 +30,7 @@ REQUIRE_MZ=${REQUIRE_MZ:=yes} REQUIRE_MTOOLS=${REQUIRE_MTOOLS:=no} STABLE_MAC_ADDRS=${STABLE_MAC_ADDRS:=no} TCPDUMP_EXTRA_FLAGS=${TCPDUMP_EXTRA_FLAGS:=} +TROUTE6=${TROUTE6:=traceroute6} relative_path="${BASH_SOURCE%/*}" if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then -- cgit v1.2.3 From 66e131861ab7bf754b50813216f5c6885cd32d63 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:52 +0300 Subject: selftests: forwarding: Add a helper to skip test when using veth pairs A handful of tests require physical loopbacks to be used instead of veth pairs. Add a helper that these tests will invoke in order to be skipped when executed with veth pairs. Fixes: 64916b57c0b1 ("selftests: forwarding: Add speed and auto-negotiation test") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-7-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/lib.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 40a8c1541b7f..f69015bf2dea 100755 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -164,6 +164,17 @@ check_port_mab_support() fi } +skip_on_veth() +{ + local kind=$(ip -j -d link show dev ${NETIFS[p1]} | + jq -r '.[].linkinfo.info_kind') + + if [[ $kind == veth ]]; then + echo "SKIP: Test cannot be run with veth pairs" + exit $ksft_skip + fi +} + if [[ "$(id -u)" -ne 0 ]]; then echo "SKIP: need root privileges" exit $ksft_skip -- cgit v1.2.3 From 60a36e21915c31c0375d9427be9406aa8ce2ec34 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:53 +0300 Subject: selftests: forwarding: ethtool: Skip when using veth pairs Auto-negotiation cannot be tested with veth pairs, resulting in failures: # ./ethtool.sh TEST: force of same speed autoneg off [FAIL] error in configuration. swp1 speed Not autoneg off [...] Fix by skipping the test when used with veth pairs. Fixes: 64916b57c0b1 ("selftests: forwarding: Add speed and auto-negotiation test") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-8-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/ethtool.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/ethtool.sh b/tools/testing/selftests/net/forwarding/ethtool.sh index dbb9fcf759e0..aa2eafb7b243 100755 --- a/tools/testing/selftests/net/forwarding/ethtool.sh +++ b/tools/testing/selftests/net/forwarding/ethtool.sh @@ -286,6 +286,8 @@ different_speeds_autoneg_on() ethtool -s $h1 autoneg on } +skip_on_veth + trap cleanup EXIT setup_prepare -- cgit v1.2.3 From b3d9305e60d121dac20a77b6847c4cf14a4c0001 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:54 +0300 Subject: selftests: forwarding: ethtool_extended_state: Skip when using veth pairs Ethtool extended state cannot be tested with veth pairs, resulting in failures: # ./ethtool_extended_state.sh TEST: Autoneg, No partner detected [FAIL] Expected "Autoneg", got "Link detected: no" [...] Fix by skipping the test when used with veth pairs. Fixes: 7d10bcce98cd ("selftests: forwarding: Add tests for ethtool extended state") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-9-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/ethtool_extended_state.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/ethtool_extended_state.sh b/tools/testing/selftests/net/forwarding/ethtool_extended_state.sh index 072faa77f53b..17f89c3b7c02 100755 --- a/tools/testing/selftests/net/forwarding/ethtool_extended_state.sh +++ b/tools/testing/selftests/net/forwarding/ethtool_extended_state.sh @@ -108,6 +108,8 @@ no_cable() ip link set dev $swp3 down } +skip_on_veth + setup_prepare tests_run -- cgit v1.2.3 From 9a711cde07c245a163d95eee5b42ed1871e73236 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:55 +0300 Subject: selftests: forwarding: hw_stats_l3_gre: Skip when using veth pairs Layer 3 hardware stats cannot be used when the underlying interfaces are veth pairs, resulting in failures: # ./hw_stats_l3_gre.sh TEST: ping gre flat [ OK ] TEST: Test rx packets: [FAIL] Traffic not reflected in the counter: 0 -> 0 TEST: Test tx packets: [FAIL] Traffic not reflected in the counter: 0 -> 0 Fix by skipping the test when used with veth pairs. Fixes: 813f97a26860 ("selftests: forwarding: Add a tunnel-based test for L3 HW stats") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-10-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh b/tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh index eb9ec4a68f84..7594bbb49029 100755 --- a/tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh +++ b/tools/testing/selftests/net/forwarding/hw_stats_l3_gre.sh @@ -99,6 +99,8 @@ test_stats_rx() test_stats g2a rx } +skip_on_veth + trap cleanup EXIT setup_prepare -- cgit v1.2.3 From 23fb886a1ced6f885ddd541cc86d45c415ce705c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:56 +0300 Subject: selftests: forwarding: ethtool_mm: Skip when MAC Merge is not supported MAC Merge cannot be tested with veth pairs, resulting in failures: # ./ethtool_mm.sh [...] TEST: Manual configuration with verification: swp1 to swp2 [FAIL] Verification did not succeed Fix by skipping the test when the interfaces do not support MAC Merge. Fixes: e6991384ace5 ("selftests: forwarding: add a test for MAC Merge layer") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-11-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/ethtool_mm.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/ethtool_mm.sh b/tools/testing/selftests/net/forwarding/ethtool_mm.sh index c580ad623848..39e736f30322 100755 --- a/tools/testing/selftests/net/forwarding/ethtool_mm.sh +++ b/tools/testing/selftests/net/forwarding/ethtool_mm.sh @@ -258,11 +258,6 @@ h2_destroy() setup_prepare() { - check_ethtool_mm_support - check_tc_fp_support - require_command lldptool - bail_on_lldpad "autoconfigure the MAC Merge layer" "configure it manually" - h1=${NETIFS[p1]} h2=${NETIFS[p2]} @@ -278,6 +273,19 @@ cleanup() h1_destroy } +check_ethtool_mm_support +check_tc_fp_support +require_command lldptool +bail_on_lldpad "autoconfigure the MAC Merge layer" "configure it manually" + +for netif in ${NETIFS[@]}; do + ethtool --show-mm $netif 2>&1 &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: $netif does not support MAC Merge" + exit $ksft_skip + fi +done + trap cleanup EXIT setup_prepare -- cgit v1.2.3 From 5e8670610b93158ffacc3241f835454ff26a3469 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:57 +0300 Subject: selftests: forwarding: tc_actions: Use ncat instead of nc The test relies on 'nc' being the netcat version from the nmap project. While this seems to be the case on Fedora, it is not the case on Ubuntu, resulting in failures such as [1]. Fix by explicitly using the 'ncat' utility from the nmap project and the skip the test in case it is not installed. [1] # timeout set to 0 # selftests: net/forwarding: tc_actions.sh # TEST: gact drop and ok (skip_hw) [ OK ] # TEST: mirred egress flower redirect (skip_hw) [ OK ] # TEST: mirred egress flower mirror (skip_hw) [ OK ] # TEST: mirred egress matchall mirror (skip_hw) [ OK ] # TEST: mirred_egress_to_ingress (skip_hw) [ OK ] # nc: invalid option -- '-' # usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl] # [-m minttl] [-O length] [-P proxy_username] [-p source_port] # [-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit] # [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]] # [destination] [port] # nc: invalid option -- '-' # usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl] # [-m minttl] [-O length] [-P proxy_username] [-p source_port] # [-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit] # [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]] # [destination] [port] # TEST: mirred_egress_to_ingress_tcp (skip_hw) [FAIL] # server output check failed # INFO: Could not test offloaded functionality not ok 80 selftests: net/forwarding: tc_actions.sh # exit=1 Fixes: ca22da2fbd69 ("act_mirred: use the backlog for nested calls to mirred ingress") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-12-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/tc_actions.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index a96cff8e7219..b0f5e55d2d0b 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -9,6 +9,8 @@ NUM_NETIFS=4 source tc_common.sh source lib.sh +require_command ncat + tcflags="skip_hw" h1_create() @@ -220,9 +222,9 @@ mirred_egress_to_ingress_tcp_test() ip_proto icmp \ action drop - ip vrf exec v$h1 nc --recv-only -w10 -l -p 12345 -o $mirred_e2i_tf2 & + ip vrf exec v$h1 ncat --recv-only -w10 -l -p 12345 -o $mirred_e2i_tf2 & local rpid=$! - ip vrf exec v$h1 nc -w1 --send-only 192.0.2.2 12345 <$mirred_e2i_tf1 + ip vrf exec v$h1 ncat -w1 --send-only 192.0.2.2 12345 <$mirred_e2i_tf1 wait -n $rpid cmp -s $mirred_e2i_tf1 $mirred_e2i_tf2 check_err $? "server output check failed" -- cgit v1.2.3 From 9ee37e53e7687654b487fc94e82569377272a7a8 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:58 +0300 Subject: selftests: forwarding: tc_flower: Relax success criterion The test checks that filters that match on source or destination MAC were only hit once. A host can send more than one packet with a given source or destination MAC, resulting in failures. Fix by relaxing the success criterion and instead check that the filters were not hit zero times. Using tc_check_at_least_x_packets() is also an option, but it is not available in older kernels. Fixes: 07e5c75184a1 ("selftests: forwarding: Introduce tc flower matching tests") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-13-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/tc_flower.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh index 683711f41aa9..b1daad19b01e 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower.sh @@ -52,8 +52,8 @@ match_dst_mac_test() tc_check_packets "dev $h2 ingress" 101 1 check_fail $? "Matched on a wrong filter" - tc_check_packets "dev $h2 ingress" 102 1 - check_err $? "Did not match on correct filter" + tc_check_packets "dev $h2 ingress" 102 0 + check_fail $? "Did not match on correct filter" tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower @@ -78,8 +78,8 @@ match_src_mac_test() tc_check_packets "dev $h2 ingress" 101 1 check_fail $? "Matched on a wrong filter" - tc_check_packets "dev $h2 ingress" 102 1 - check_err $? "Did not match on correct filter" + tc_check_packets "dev $h2 ingress" 102 0 + check_fail $? "Did not match on correct filter" tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower -- cgit v1.2.3 From 11604178fdc3404d46518e5332f1fe865d30c4a1 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:14:59 +0300 Subject: selftests: forwarding: tc_tunnel_key: Make filters more specific The test installs filters that match on various IP fragments (e.g., no fragment, first fragment) and expects a certain amount of packets to hit each filter. This is problematic as the filters are not specific enough and can match IP packets (e.g., IGMP) generated by the stack, resulting in failures [1]. Fix by making the filters more specific and match on more fields in the IP header: Source IP, destination IP and protocol. [1] # timeout set to 0 # selftests: net/forwarding: tc_tunnel_key.sh # TEST: tunnel_key nofrag (skip_hw) [FAIL] # packet smaller than MTU was not tunneled # INFO: Could not test offloaded functionality not ok 89 selftests: net/forwarding: tc_tunnel_key.sh # exit=1 Fixes: 533a89b1940f ("selftests: forwarding: add tunnel_key "nofrag" test case") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Tested-by: Mirsad Todorovac Acked-by: Davide Caratti Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-14-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/tc_tunnel_key.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_tunnel_key.sh b/tools/testing/selftests/net/forwarding/tc_tunnel_key.sh index 5ac184d51809..5a5dd9034819 100755 --- a/tools/testing/selftests/net/forwarding/tc_tunnel_key.sh +++ b/tools/testing/selftests/net/forwarding/tc_tunnel_key.sh @@ -104,11 +104,14 @@ tunnel_key_nofrag_test() local i tc filter add dev $swp1 ingress protocol ip pref 100 handle 100 \ - flower ip_flags nofrag action drop + flower src_ip 192.0.2.1 dst_ip 192.0.2.2 ip_proto udp \ + ip_flags nofrag action drop tc filter add dev $swp1 ingress protocol ip pref 101 handle 101 \ - flower ip_flags firstfrag action drop + flower src_ip 192.0.2.1 dst_ip 192.0.2.2 ip_proto udp \ + ip_flags firstfrag action drop tc filter add dev $swp1 ingress protocol ip pref 102 handle 102 \ - flower ip_flags nofirstfrag action drop + flower src_ip 192.0.2.1 dst_ip 192.0.2.2 ip_proto udp \ + ip_flags nofirstfrag action drop # test 'nofrag' set tc filter add dev h1-et egress protocol all pref 1 handle 1 matchall $tcflags \ -- cgit v1.2.3 From 21a72166abb9c9d13fe24a07cef0a0b9f1e331b0 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:15:00 +0300 Subject: selftests: forwarding: tc_flower_l2_miss: Fix failing test with old libnet As explained in commit 8bcfb4ae4d97 ("selftests: forwarding: Fix failing tests with old libnet"), old versions of libnet (used by mausezahn) do not use the "SO_BINDTODEVICE" socket option. For IP unicast packets, this can be solved by prefixing mausezahn invocations with "ip vrf exec". However, IP multicast packets do not perform routing and simply egress the bound device, which does not exist in this case. Fix by specifying the source and destination MAC of the packet which will cause mausezahn to use a packet socket instead of an IP socket. Fixes: 8c33266ae26a ("selftests: forwarding: Add layer 2 miss test cases") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-15-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh index e22c2d28b6eb..20a7cb7222b8 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -127,6 +127,7 @@ test_l2_miss_multicast_common() local proto=$1; shift local sip=$1; shift local dip=$1; shift + local dmac=$1; shift local mode=$1; shift local name=$1; shift @@ -142,7 +143,7 @@ test_l2_miss_multicast_common() action pass # Before adding MDB entry. - $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q tc_check_packets "dev $swp2 egress" 101 1 check_err $? "Unregistered multicast filter was not hit before adding MDB entry" @@ -153,7 +154,7 @@ test_l2_miss_multicast_common() # Adding MDB entry. bridge mdb replace dev br1 port $swp2 grp $dip permanent - $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q tc_check_packets "dev $swp2 egress" 101 1 check_err $? "Unregistered multicast filter was hit after adding MDB entry" @@ -164,7 +165,7 @@ test_l2_miss_multicast_common() # Deleting MDB entry. bridge mdb del dev br1 port $swp2 grp $dip - $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q tc_check_packets "dev $swp2 egress" 101 2 check_err $? "Unregistered multicast filter was not hit after deleting MDB entry" @@ -183,10 +184,11 @@ test_l2_miss_multicast_ipv4() local proto="ipv4" local sip=192.0.2.1 local dip=239.1.1.1 + local dmac=01:00:5e:01:01:01 local mode="-4" local name="IPv4" - test_l2_miss_multicast_common $proto $sip $dip $mode $name + test_l2_miss_multicast_common $proto $sip $dip $dmac $mode $name } test_l2_miss_multicast_ipv6() @@ -194,10 +196,11 @@ test_l2_miss_multicast_ipv6() local proto="ipv6" local sip=2001:db8:1::1 local dip=ff0e::1 + local dmac=33:33:00:00:00:01 local mode="-6" local name="IPv6" - test_l2_miss_multicast_common $proto $sip $dip $mode $name + test_l2_miss_multicast_common $proto $sip $dip $dmac $mode $name } test_l2_miss_multicast() -- cgit v1.2.3 From e98e195d90cc93b1bf2ad762c7c274a40dab7173 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:15:01 +0300 Subject: selftests: forwarding: bridge_mdb: Fix failing test with old libnet As explained in commit 8bcfb4ae4d97 ("selftests: forwarding: Fix failing tests with old libnet"), old versions of libnet (used by mausezahn) do not use the "SO_BINDTODEVICE" socket option. For IP unicast packets, this can be solved by prefixing mausezahn invocations with "ip vrf exec". However, IP multicast packets do not perform routing and simply egress the bound device, which does not exist in this case. Fix by specifying the source and destination MAC of the packet which will cause mausezahn to use a packet socket instead of an IP socket. Fixes: b6d00da08610 ("selftests: forwarding: Add bridge MDB test") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-16-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/forwarding/bridge_mdb.sh | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh index 6f830b5f03c9..4853b8e4f8d3 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh @@ -850,6 +850,7 @@ cfg_test() __fwd_test_host_ip() { local grp=$1; shift + local dmac=$1; shift local src=$1; shift local mode=$1; shift local name @@ -872,27 +873,27 @@ __fwd_test_host_ip() # Packet should only be flooded to multicast router ports when there is # no matching MDB entry. The bridge is not configured as a multicast # router port. - $MZ $mode $h1.10 -c 1 -p 128 -A $src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q tc_check_packets "dev br0 ingress" 1 0 check_err $? "Packet locally received after flood" # Install a regular port group entry and expect the packet to not be # locally received. bridge mdb add dev br0 port $swp2 grp $grp temp vid 10 - $MZ $mode $h1.10 -c 1 -p 128 -A $src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q tc_check_packets "dev br0 ingress" 1 0 check_err $? "Packet locally received after installing a regular entry" # Add a host entry and expect the packet to be locally received. bridge mdb add dev br0 port br0 grp $grp temp vid 10 - $MZ $mode $h1.10 -c 1 -p 128 -A $src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q tc_check_packets "dev br0 ingress" 1 1 check_err $? "Packet not locally received after adding a host entry" # Remove the host entry and expect the packet to not be locally # received. bridge mdb del dev br0 port br0 grp $grp vid 10 - $MZ $mode $h1.10 -c 1 -p 128 -A $src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q tc_check_packets "dev br0 ingress" 1 1 check_err $? "Packet locally received after removing a host entry" @@ -905,8 +906,8 @@ __fwd_test_host_ip() fwd_test_host_ip() { - __fwd_test_host_ip "239.1.1.1" "192.0.2.1" "-4" - __fwd_test_host_ip "ff0e::1" "2001:db8:1::1" "-6" + __fwd_test_host_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "-4" + __fwd_test_host_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "-6" } fwd_test_host_l2() @@ -966,6 +967,7 @@ fwd_test_host() __fwd_test_port_ip() { local grp=$1; shift + local dmac=$1; shift local valid_src=$1; shift local invalid_src=$1; shift local mode=$1; shift @@ -999,43 +1001,43 @@ __fwd_test_port_ip() vlan_ethtype $eth_type vlan_id 10 dst_ip $grp \ src_ip $invalid_src action drop - $MZ $mode $h1.10 -c 1 -p 128 -A $valid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 1 0 check_err $? "Packet from valid source received on H2 before adding entry" - $MZ $mode $h1.10 -c 1 -p 128 -A $invalid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 2 0 check_err $? "Packet from invalid source received on H2 before adding entry" bridge mdb add dev br0 port $swp2 grp $grp vid 10 \ filter_mode $filter_mode source_list $src_list - $MZ $mode $h1.10 -c 1 -p 128 -A $valid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 1 1 check_err $? "Packet from valid source not received on H2 after adding entry" - $MZ $mode $h1.10 -c 1 -p 128 -A $invalid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 2 0 check_err $? "Packet from invalid source received on H2 after adding entry" bridge mdb replace dev br0 port $swp2 grp $grp vid 10 \ filter_mode exclude - $MZ $mode $h1.10 -c 1 -p 128 -A $valid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 1 2 check_err $? "Packet from valid source not received on H2 after allowing all sources" - $MZ $mode $h1.10 -c 1 -p 128 -A $invalid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 2 1 check_err $? "Packet from invalid source not received on H2 after allowing all sources" bridge mdb del dev br0 port $swp2 grp $grp vid 10 - $MZ $mode $h1.10 -c 1 -p 128 -A $valid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 1 2 check_err $? "Packet from valid source received on H2 after deleting entry" - $MZ $mode $h1.10 -c 1 -p 128 -A $invalid_src -B $grp -t udp -q + $MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q tc_check_packets "dev $h2 ingress" 2 1 check_err $? "Packet from invalid source received on H2 after deleting entry" @@ -1047,11 +1049,11 @@ __fwd_test_port_ip() fwd_test_port_ip() { - __fwd_test_port_ip "239.1.1.1" "192.0.2.1" "192.0.2.2" "-4" "exclude" - __fwd_test_port_ip "ff0e::1" "2001:db8:1::1" "2001:db8:1::2" "-6" \ + __fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "exclude" + __fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \ "exclude" - __fwd_test_port_ip "239.1.1.1" "192.0.2.1" "192.0.2.2" "-4" "include" - __fwd_test_port_ip "ff0e::1" "2001:db8:1::1" "2001:db8:1::2" "-6" \ + __fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "include" + __fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \ "include" } @@ -1127,7 +1129,7 @@ ctrl_igmpv3_is_in_test() filter_mode include source_list 192.0.2.1 # IS_IN ( 192.0.2.2 ) - $MZ $h1.10 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ + $MZ $h1.10 -c 1 -a own -b 01:00:5e:01:01:01 -A 192.0.2.1 -B 239.1.1.1 \ -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -q 192.0.2.2 @@ -1140,7 +1142,7 @@ ctrl_igmpv3_is_in_test() filter_mode include source_list 192.0.2.1 # IS_IN ( 192.0.2.2 ) - $MZ $h1.10 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ + $MZ $h1.10 -a own -b 01:00:5e:01:01:01 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -v "src" | \ @@ -1167,7 +1169,7 @@ ctrl_mldv2_is_in_test() # IS_IN ( 2001:db8:1::2 ) local p=$(mldv2_is_in_get fe80::1 ff0e::1 2001:db8:1::2) - $MZ -6 $h1.10 -c 1 -A fe80::1 -B ff0e::1 \ + $MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \ -t ip hop=1,next=0,p="$p" -q bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \ @@ -1181,7 +1183,7 @@ ctrl_mldv2_is_in_test() filter_mode include source_list 2001:db8:1::1 # IS_IN ( 2001:db8:1::2 ) - $MZ -6 $h1.10 -c 1 -A fe80::1 -B ff0e::1 \ + $MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \ -t ip hop=1,next=0,p="$p" -q bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | grep -v "src" | \ -- cgit v1.2.3 From cb034948ac292da82cc0e6bc1340f81be36e117d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:15:02 +0300 Subject: selftests: forwarding: bridge_mdb_max: Fix failing test with old libnet As explained in commit 8bcfb4ae4d97 ("selftests: forwarding: Fix failing tests with old libnet"), old versions of libnet (used by mausezahn) do not use the "SO_BINDTODEVICE" socket option. For IP unicast packets, this can be solved by prefixing mausezahn invocations with "ip vrf exec". However, IP multicast packets do not perform routing and simply egress the bound device, which does not exist in this case. Fix by specifying the source and destination MAC of the packet which will cause mausezahn to use a packet socket instead of an IP socket. Fixes: 3446dcd7df05 ("selftests: forwarding: bridge_mdb_max: Add a new selftest") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-17-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/bridge_mdb_max.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh b/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh index fa762b716288..3da9d93ab36f 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb_max.sh @@ -252,7 +252,8 @@ ctl4_entries_add() local IPs=$(seq -f 192.0.2.%g 1 $((n - 1))) local peer=$(locus_dev_peer $locus) local GRP=239.1.1.${grp} - $MZ $peer -c 1 -A 192.0.2.1 -B $GRP \ + local dmac=01:00:5e:01:01:$(printf "%02x" $grp) + $MZ $peer -a own -b $dmac -c 1 -A 192.0.2.1 -B $GRP \ -t ip proto=2,p=$(igmpv3_is_in_get $GRP $IPs) -q sleep 1 @@ -272,7 +273,8 @@ ctl4_entries_del() local peer=$(locus_dev_peer $locus) local GRP=239.1.1.${grp} - $MZ $peer -c 1 -A 192.0.2.1 -B 224.0.0.2 \ + local dmac=01:00:5e:00:00:02 + $MZ $peer -a own -b $dmac -c 1 -A 192.0.2.1 -B 224.0.0.2 \ -t ip proto=2,p=$(igmpv2_leave_get $GRP) -q sleep 1 ! bridge mdb show dev br0 | grep -q $GRP @@ -289,8 +291,10 @@ ctl6_entries_add() local peer=$(locus_dev_peer $locus) local SIP=fe80::1 local GRP=ff0e::${grp} + local dmac=33:33:00:00:00:$(printf "%02x" $grp) local p=$(mldv2_is_in_get $SIP $GRP $IPs) - $MZ -6 $peer -c 1 -A $SIP -B $GRP -t ip hop=1,next=0,p="$p" -q + $MZ -6 $peer -a own -b $dmac -c 1 -A $SIP -B $GRP \ + -t ip hop=1,next=0,p="$p" -q sleep 1 local nn=$(bridge mdb show dev br0 | grep $GRP | wc -l) @@ -310,8 +314,10 @@ ctl6_entries_del() local peer=$(locus_dev_peer $locus) local SIP=fe80::1 local GRP=ff0e::${grp} + local dmac=33:33:00:00:00:$(printf "%02x" $grp) local p=$(mldv1_done_get $SIP $GRP) - $MZ -6 $peer -c 1 -A $SIP -B $GRP -t ip hop=1,next=0,p="$p" -q + $MZ -6 $peer -a own -b $dmac -c 1 -A $SIP -B $GRP \ + -t ip hop=1,next=0,p="$p" -q sleep 1 ! bridge mdb show dev br0 | grep -q $GRP } -- cgit v1.2.3 From 8b5ff37097775cdbd447442603957066dd2e4d02 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Aug 2023 17:15:03 +0300 Subject: selftests: forwarding: bridge_mdb: Make test more robust Some test cases check that the group timer is (or isn't) 0. Instead of grepping for "0.00" grep for " 0.00" as the former can also match "260.00" which is the default group membership interval. Fixes: b6d00da08610 ("selftests: forwarding: Add bridge MDB test") Reported-by: Mirsad Todorovac Closes: https://lore.kernel.org/netdev/adc5e40d-d040-a65e-eb26-edf47dac5b02@alu.unizg.hr/ Signed-off-by: Ido Schimmel Tested-by: Mirsad Todorovac Reviewed-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20230808141503.4060661-18-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/bridge_mdb.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh index 4853b8e4f8d3..d0c6c499d5da 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh @@ -617,7 +617,7 @@ __cfg_test_port_ip_sg() grep -q "permanent" check_err $? "Entry not added as \"permanent\" when should" bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ - grep -q "0.00" + grep -q " 0.00" check_err $? "\"permanent\" entry has a pending group timer" bridge mdb del dev br0 port $swp1 $grp_key vid 10 @@ -626,7 +626,7 @@ __cfg_test_port_ip_sg() grep -q "temp" check_err $? "Entry not added as \"temp\" when should" bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ - grep -q "0.00" + grep -q " 0.00" check_fail $? "\"temp\" entry has an unpending group timer" bridge mdb del dev br0 port $swp1 $grp_key vid 10 @@ -659,7 +659,7 @@ __cfg_test_port_ip_sg() grep -q "permanent" check_err $? "Entry not marked as \"permanent\" after replace" bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ - grep -q "0.00" + grep -q " 0.00" check_err $? "Entry has a pending group timer after replace" bridge mdb replace dev br0 port $swp1 $grp_key vid 10 temp @@ -667,7 +667,7 @@ __cfg_test_port_ip_sg() grep -q "temp" check_err $? "Entry not marked as \"temp\" after replace" bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ - grep -q "0.00" + grep -q " 0.00" check_fail $? "Entry has an unpending group timer after replace" bridge mdb del dev br0 port $swp1 $grp_key vid 10 -- cgit v1.2.3 From 2bc057692599a5b3dc93d75a3dff34f72576355d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 8 Aug 2023 11:06:17 -0600 Subject: block: don't make REQ_POLLED imply REQ_NOWAIT Normally these two flags do go together, as the issuer of polled IO generally cannot wait for resources that will get freed as part of IO completion. This is because that very task is the one that will complete the request and free those resources, hence that would introduce a deadlock. But it is possible to have someone else issue the polled IO, eg via io_uring if the request is punted to io-wq. For that case, it's fine to have the task block on IO submission, as it is not the same task that will be completing the IO. It's completely up to the caller to ask for both polled and nowait IO separately! If we don't allow polled IO where IOCB_NOWAIT isn't set in the kiocb, then we can run into repeated -EAGAIN submissions and not make any progress. Reviewed-by: Bart Van Assche Signed-off-by: Jens Axboe --- block/fops.c | 7 ++++--- include/linux/bio.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/block/fops.c b/block/fops.c index a286bf3325c5..838ffada5341 100644 --- a/block/fops.c +++ b/block/fops.c @@ -358,13 +358,14 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb, task_io_account_write(bio->bi_iter.bi_size); } + if (iocb->ki_flags & IOCB_NOWAIT) + bio->bi_opf |= REQ_NOWAIT; + if (iocb->ki_flags & IOCB_HIPRI) { - bio->bi_opf |= REQ_POLLED | REQ_NOWAIT; + bio->bi_opf |= REQ_POLLED; submit_bio(bio); WRITE_ONCE(iocb->private, bio); } else { - if (iocb->ki_flags & IOCB_NOWAIT) - bio->bi_opf |= REQ_NOWAIT; submit_bio(bio); } return -EIOCBQUEUED; diff --git a/include/linux/bio.h b/include/linux/bio.h index c4f5b5228105..11984ed29cb8 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -791,7 +791,7 @@ static inline int bio_integrity_add_page(struct bio *bio, struct page *page, static inline void bio_set_polled(struct bio *bio, struct kiocb *kiocb) { bio->bi_opf |= REQ_POLLED; - if (!is_sync_kiocb(kiocb)) + if (kiocb->ki_flags & IOCB_NOWAIT) bio->bi_opf |= REQ_NOWAIT; } -- cgit v1.2.3 From f099a108cabf72a1184b1e14e4a09f4ca3375750 Mon Sep 17 00:00:00 2001 From: Chengming Zhou Date: Fri, 4 Aug 2023 15:06:09 +0800 Subject: blk-iocost: fix queue stats accounting The q->stats->accounting is not only used by iocost, but iocost only increase this counter, never decrease it. So queue stats accounting will always enabled after using iocost once. Signed-off-by: Chengming Zhou Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20230804070609.31623-1-chengming.zhou@linux.dev Signed-off-by: Jens Axboe --- block/blk-iocost.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/block/blk-iocost.c b/block/blk-iocost.c index dd64e2066f01..089fcb9cfce3 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -3301,11 +3301,12 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input, if (qos[QOS_MIN] > qos[QOS_MAX]) goto einval; - if (enable) { + if (enable && !ioc->enabled) { blk_stat_enable_accounting(disk->queue); blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue); ioc->enabled = true; - } else { + } else if (!enable && ioc->enabled) { + blk_stat_disable_accounting(disk->queue); blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue); ioc->enabled = false; } -- cgit v1.2.3 From 048c796beb6eb4fa3a5a647ee1c81f5c6f0f6a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 7 Aug 2023 03:25:32 -0700 Subject: ipv6: adjust ndisc_is_useropt() to also return true for PIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upcoming (and nearly finalized): https://datatracker.ietf.org/doc/draft-collink-6man-pio-pflag/ will update the IPv6 RA to include a new flag in the PIO field, which will serve as a hint to perform DHCPv6-PD. As we don't want DHCPv6 related logic inside the kernel, this piece of information needs to be exposed to userspace. The simplest option is to simply expose the entire PIO through the already existing mechanism. Even without this new flag, the already existing PIO R (router address) flag (from RFC6275) cannot AFAICT be handled entirely in kernel, and provides useful information that should be exposed to userspace (the router's global address, for use by Mobile IPv6). Also cc'ing stable@ for inclusion in LTS, as while technically this is not quite a bugfix, and instead more of a feature, it is absolutely trivial and the alternative is manually cherrypicking into all Android Common Kernel trees - and I know Greg will ask for it to be sent in via LTS instead... Cc: Jen Linkova Cc: Lorenzo Colitti Cc: David Ahern Cc: YOSHIFUJI Hideaki / ć‰è—€è‹±æ˜Ž Cc: stable@vger.kernel.org Signed-off-by: Maciej Ć»enczykowski Link: https://lore.kernel.org/r/20230807102533.1147559-1-maze@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ndisc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 18634ebd20a4..a42be96ae209 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -197,7 +197,8 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, static inline int ndisc_is_useropt(const struct net_device *dev, struct nd_opt_hdr *opt) { - return opt->nd_opt_type == ND_OPT_RDNSS || + return opt->nd_opt_type == ND_OPT_PREFIX_INFO || + opt->nd_opt_type == ND_OPT_RDNSS || opt->nd_opt_type == ND_OPT_DNSSL || opt->nd_opt_type == ND_OPT_CAPTIVE_PORTAL || opt->nd_opt_type == ND_OPT_PREF64 || -- cgit v1.2.3 From 9c28423d3caae63e665e2b8d704fa41ac823b2a6 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 9 Aug 2023 11:12:07 -0700 Subject: ASoC: SOF: Intel: Initialize chip in hda_sdw_check_wakeen_irq() Clang warns (or errors with CONFIG_WERROR): sound/soc/sof/intel/hda.c:423:6: error: variable 'chip' is uninitialized when used here [-Werror,-Wuninitialized] 423 | if (chip && chip->check_sdw_wakeen_irq) | ^~~~ sound/soc/sof/intel/hda.c:418:39: note: initialize the variable 'chip' to silence this warning 418 | const struct sof_intel_dsp_desc *chip; | ^ | = NULL 1 error generated. Add the missing initialization, following the pattern of the other irq functions. Fixes: 9362ab78f175 ("ASoC: SOF: Intel: add abstraction for SoundWire wake-ups") Signed-off-by: Nathan Chancellor Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230809-intel-hda-missing-chip-init-v1-1-61557ca6fa8a@kernel.org Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 04c748a72b13..15e6779efaa3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -420,6 +420,7 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) return false; + chip = get_chip_info(sdev->pdata); if (chip && chip->check_sdw_wakeen_irq) return chip->check_sdw_wakeen_irq(sdev); -- cgit v1.2.3 From 85c2c79a07302fe68a1ad5cc449458cc559e314d Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Wed, 9 Aug 2023 16:28:43 +0200 Subject: xsk: fix refcount underflow in error path Fix a refcount underflow problem reported by syzbot that can happen when a system is running out of memory. If xp_alloc_tx_descs() fails, and it can only fail due to not having enough memory, then the error path is triggered. In this error path, the refcount of the pool is decremented as it has incremented before. However, the reference to the pool in the socket was not nulled. This means that when the socket is closed later, the socket teardown logic will think that there is a pool attached to the socket and try to decrease the refcount again, leading to a refcount underflow. I chose this fix as it involved adding just a single line. Another option would have been to move xp_get_pool() and the assignment of xs->pool to after the if-statement and using xs_umem->pool instead of xs->pool in the whole if-statement resulting in somewhat simpler code, but this would have led to much more churn in the code base perhaps making it harder to backport. Fixes: ba3beec2ec1d ("xsk: Fix possible crash when multiple sockets are created") Reported-by: syzbot+8ada0057e69293a05fd4@syzkaller.appspotmail.com Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230809142843.13944-1-magnus.karlsson@gmail.com Signed-off-by: Martin KaFai Lau --- net/xdp/xsk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index b89adb52a977..10ea85c03147 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -994,6 +994,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) err = xp_alloc_tx_descs(xs->pool, xs); if (err) { xp_put_pool(xs->pool); + xs->pool = NULL; sockfd_put(sock); goto out_unlock; } -- cgit v1.2.3 From 7e96ec0e6605b69bb21bbf6c0ff9051e656ec2b1 Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Fri, 4 Aug 2023 03:37:37 -0400 Subject: bpf, sockmap: Fix map type error in sock_map_del_link sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although both types have member named "progs", the offset of "progs" member in these two types is different, so "progs" should be accessed with the real map type. Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface") Signed-off-by: Xu Kuohai Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20230804073740.194770-2-xukuohai@huaweicloud.com Signed-off-by: Martin KaFai Lau --- net/core/sock_map.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 08ab108206bf..8f07fea39d9e 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -146,13 +146,13 @@ static void sock_map_del_link(struct sock *sk, list_for_each_entry_safe(link, tmp, &psock->link, list) { if (link->link_raw == link_raw) { struct bpf_map *map = link->map; - struct bpf_stab *stab = container_of(map, struct bpf_stab, - map); - if (psock->saved_data_ready && stab->progs.stream_parser) + struct sk_psock_progs *progs = sock_map_progs(map); + + if (psock->saved_data_ready && progs->stream_parser) strp_stop = true; - if (psock->saved_data_ready && stab->progs.stream_verdict) + if (psock->saved_data_ready && progs->stream_verdict) verdict_stop = true; - if (psock->saved_data_ready && stab->progs.skb_verdict) + if (psock->saved_data_ready && progs->skb_verdict) verdict_stop = true; list_del(&link->list); sk_psock_free_link(link); -- cgit v1.2.3 From 809e4dc71a0f2b8d2836035d98603694fff11d5d Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Fri, 4 Aug 2023 03:37:38 -0400 Subject: bpf, sockmap: Fix bug that strp_done cannot be called strp_done is only called when psock->progs.stream_parser is not NULL, but stream_parser was set to NULL by sk_psock_stop_strp(), called by sk_psock_drop() earlier. So, strp_done can never be called. Introduce SK_PSOCK_RX_ENABLED to mark whether there is strp on psock. Change the condition for calling strp_done from judging whether stream_parser is set to judging whether this flag is set. This flag is only set once when strp_init() succeeds, and will never be cleared later. Fixes: c0d95d3380ee ("bpf, sockmap: Re-evaluate proto ops when psock is removed from sockmap") Signed-off-by: Xu Kuohai Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20230804073740.194770-3-xukuohai@huaweicloud.com Signed-off-by: Martin KaFai Lau --- include/linux/skmsg.h | 1 + net/core/skmsg.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 054d7911bfc9..c1637515a8a4 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -62,6 +62,7 @@ struct sk_psock_progs { enum sk_psock_state_bits { SK_PSOCK_TX_ENABLED, + SK_PSOCK_RX_STRP_ENABLED, }; struct sk_psock_link { diff --git a/net/core/skmsg.c b/net/core/skmsg.c index a29508e1ff35..ef1a2eb6520b 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1120,13 +1120,19 @@ static void sk_psock_strp_data_ready(struct sock *sk) int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock) { + int ret; + static const struct strp_callbacks cb = { .rcv_msg = sk_psock_strp_read, .read_sock_done = sk_psock_strp_read_done, .parse_msg = sk_psock_strp_parse, }; - return strp_init(&psock->strp, sk, &cb); + ret = strp_init(&psock->strp, sk, &cb); + if (!ret) + sk_psock_set_state(psock, SK_PSOCK_RX_STRP_ENABLED); + + return ret; } void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock) @@ -1154,7 +1160,7 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock) static void sk_psock_done_strp(struct sk_psock *psock) { /* Parser has been stopped */ - if (psock->progs.stream_parser) + if (sk_psock_test_state(psock, SK_PSOCK_RX_STRP_ENABLED)) strp_done(&psock->strp); } #else -- cgit v1.2.3 From 90f0074cd9f9a24b7b6c4d5afffa676aee48c0e9 Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Fri, 4 Aug 2023 03:37:39 -0400 Subject: selftests/bpf: fix a CI failure caused by vsock sockmap test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BPF CI has reported the following failure: Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1506: ingress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1514: ingress: recv() err, errno=11 vsock_unix_redir_connectible:FAIL:1514 ./test_progs:vsock_unix_redir_connectible:1518: ingress: vsock socket map failed, a != b vsock_unix_redir_connectible:FAIL:1518 ./test_progs:vsock_unix_redir_connectible:1525: ingress: want pass count 1, have 0 It’s because the recv(... MSG_DONTWAIT) syscall in the test case is called before the queued work sk_psock_backlog() in the kernel finishes executing. So the data to be read is still queued in psock->ingress_skb and cannot be read by the user program. Therefore, the non-blocking recv() reads nothing and reports an EAGAIN error. So replace recv(... MSG_DONTWAIT) with xrecv_nonblock(), which calls select() to wait for data to be readable or timeout before calls recv(). Fixes: d61bd8c1fd02 ("selftests/bpf: add a test case for vsock sockmap") Signed-off-by: Xu Kuohai Link: https://lore.kernel.org/r/20230804073740.194770-4-xukuohai@huaweicloud.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/prog_tests/sockmap_listen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index b4f6f3a50ae5..ba35bcc66e7e 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -1432,7 +1432,7 @@ static void vsock_unix_redir_connectible(int sock_mapfd, int verd_mapfd, if (n < 1) goto out; - n = recv(mode == REDIR_INGRESS ? u0 : u1, &b, sizeof(b), MSG_DONTWAIT); + n = xrecv_nonblock(mode == REDIR_INGRESS ? u0 : u1, &b, sizeof(b), 0); if (n < 0) FAIL("%s: recv() err, errno=%d", log_prefix, errno); if (n == 0) -- cgit v1.2.3 From a4b7193d8efdfde1ea89fe34e921ad031f79f993 Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Fri, 4 Aug 2023 03:37:40 -0400 Subject: selftests/bpf: Add sockmap test for redirecting partial skb data Add a test case to check whether sockmap redirection works correctly when data length returned by stream_parser is less than skb->len. In addition, this test checks whether strp_done is called correctly. The reason is that we returns skb->len - 1 from the stream_parser, so the last byte in the skb will be held by strp->skb_head. Therefore, if strp_done is not called to free strp->skb_head, we'll get a memleak warning. Signed-off-by: Xu Kuohai Link: https://lore.kernel.org/r/20230804073740.194770-5-xukuohai@huaweicloud.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/prog_tests/sockmap_listen.c | 72 ++++++++++++++++++++++ .../selftests/bpf/progs/test_sockmap_listen.c | 14 +++++ 2 files changed, 86 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index ba35bcc66e7e..5674a9d0cacf 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -869,6 +869,77 @@ static void test_msg_redir_to_listening(struct test_sockmap_listen *skel, xbpf_prog_detach2(verdict, sock_map, BPF_SK_MSG_VERDICT); } +static void redir_partial(int family, int sotype, int sock_map, int parser_map) +{ + int s, c0, c1, p0, p1; + int err, n, key, value; + char buf[] = "abc"; + + key = 0; + value = sizeof(buf) - 1; + err = xbpf_map_update_elem(parser_map, &key, &value, 0); + if (err) + return; + + s = socket_loopback(family, sotype | SOCK_NONBLOCK); + if (s < 0) + goto clean_parser_map; + + err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1); + if (err) + goto close_srv; + + err = add_to_sockmap(sock_map, p0, p1); + if (err) + goto close; + + n = xsend(c1, buf, sizeof(buf), 0); + if (n < sizeof(buf)) + FAIL("incomplete write"); + + n = xrecv_nonblock(c0, buf, sizeof(buf), 0); + if (n != sizeof(buf) - 1) + FAIL("expect %zu, received %d", sizeof(buf) - 1, n); + +close: + xclose(c0); + xclose(p0); + xclose(c1); + xclose(p1); +close_srv: + xclose(s); + +clean_parser_map: + key = 0; + value = 0; + xbpf_map_update_elem(parser_map, &key, &value, 0); +} + +static void test_skb_redir_partial(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int family, + int sotype) +{ + int verdict = bpf_program__fd(skel->progs.prog_stream_verdict); + int parser = bpf_program__fd(skel->progs.prog_stream_parser); + int parser_map = bpf_map__fd(skel->maps.parser_map); + int sock_map = bpf_map__fd(inner_map); + int err; + + err = xbpf_prog_attach(parser, sock_map, BPF_SK_SKB_STREAM_PARSER, 0); + if (err) + return; + + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT, 0); + if (err) + goto detach; + + redir_partial(family, sotype, sock_map, parser_map); + + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT); +detach: + xbpf_prog_detach2(parser, sock_map, BPF_SK_SKB_STREAM_PARSER); +} + static void test_reuseport_select_listening(int family, int sotype, int sock_map, int verd_map, int reuseport_prog) @@ -1243,6 +1314,7 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map, } tests[] = { TEST(test_skb_redir_to_connected), TEST(test_skb_redir_to_listening), + TEST(test_skb_redir_partial), TEST(test_msg_redir_to_connected), TEST(test_msg_redir_to_listening), }; diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c index 325c9f193432..464d35bd57c7 100644 --- a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c +++ b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c @@ -28,12 +28,26 @@ struct { __type(value, unsigned int); } verdict_map SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} parser_map SEC(".maps"); + bool test_sockmap = false; /* toggled by user-space */ bool test_ingress = false; /* toggled by user-space */ SEC("sk_skb/stream_parser") int prog_stream_parser(struct __sk_buff *skb) { + int *value; + __u32 key = 0; + + value = bpf_map_lookup_elem(&parser_map, &key); + if (value && *value) + return *value; + return skb->len; } -- cgit v1.2.3 From fe9da61ffccad80ae79fadad836971acf0d465bd Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 7 Aug 2023 13:11:48 +0900 Subject: zonefs: fix synchronous direct writes to sequential files Commit 16d7fd3cfa72 ("zonefs: use iomap for synchronous direct writes") changes zonefs code from a self-built zone append BIO to using iomap for synchronous direct writes. This change relies on iomap submit BIO callback to change the write BIO built by iomap to a zone append BIO. However, this change overlooked the fact that a write BIO may be very large as it is split when issued. The change from a regular write to a zone append operation for the built BIO can result in a block layer warning as zone append BIO are not allowed to be split. WARNING: CPU: 18 PID: 202210 at block/bio.c:1644 bio_split+0x288/0x350 Call Trace: ? __warn+0xc9/0x2b0 ? bio_split+0x288/0x350 ? report_bug+0x2e6/0x390 ? handle_bug+0x41/0x80 ? exc_invalid_op+0x13/0x40 ? asm_exc_invalid_op+0x16/0x20 ? bio_split+0x288/0x350 bio_split_rw+0x4bc/0x810 ? __pfx_bio_split_rw+0x10/0x10 ? lockdep_unlock+0xf2/0x250 __bio_split_to_limits+0x1d8/0x900 blk_mq_submit_bio+0x1cf/0x18a0 ? __pfx_iov_iter_extract_pages+0x10/0x10 ? __pfx_blk_mq_submit_bio+0x10/0x10 ? find_held_lock+0x2d/0x110 ? lock_release+0x362/0x620 ? mark_held_locks+0x9e/0xe0 __submit_bio+0x1ea/0x290 ? __pfx___submit_bio+0x10/0x10 ? seqcount_lockdep_reader_access.constprop.0+0x82/0x90 submit_bio_noacct_nocheck+0x675/0xa20 ? __pfx_bio_iov_iter_get_pages+0x10/0x10 ? __pfx_submit_bio_noacct_nocheck+0x10/0x10 iomap_dio_bio_iter+0x624/0x1280 __iomap_dio_rw+0xa22/0x18a0 ? lock_is_held_type+0xe3/0x140 ? __pfx___iomap_dio_rw+0x10/0x10 ? lock_release+0x362/0x620 ? zonefs_file_write_iter+0x74c/0xc80 [zonefs] ? down_write+0x13d/0x1e0 iomap_dio_rw+0xe/0x40 zonefs_file_write_iter+0x5ea/0xc80 [zonefs] do_iter_readv_writev+0x18b/0x2c0 ? __pfx_do_iter_readv_writev+0x10/0x10 ? inode_security+0x54/0xf0 do_iter_write+0x13b/0x7c0 ? lock_is_held_type+0xe3/0x140 vfs_writev+0x185/0x550 ? __pfx_vfs_writev+0x10/0x10 ? __handle_mm_fault+0x9bd/0x1c90 ? find_held_lock+0x2d/0x110 ? lock_release+0x362/0x620 ? find_held_lock+0x2d/0x110 ? lock_release+0x362/0x620 ? __up_read+0x1ea/0x720 ? do_pwritev+0x136/0x1f0 do_pwritev+0x136/0x1f0 ? __pfx_do_pwritev+0x10/0x10 ? syscall_enter_from_user_mode+0x22/0x90 ? lockdep_hardirqs_on+0x7d/0x100 do_syscall_64+0x58/0x80 This error depends on the hardware used, specifically on the max zone append bytes and max_[hw_]sectors limits. Tests using AMD Epyc machines that have low limits did not reveal this issue while runs on Intel Xeon machines with larger limits trigger it. Manually splitting the zone append BIO using bio_split_rw() can solve this issue but also requires issuing the fragment BIOs synchronously with submit_bio_wait(), to avoid potential reordering of the zone append BIO fragments, which would lead to data corruption. That is, this solution is not better than using regular write BIOs which are subject to serialization using zone write locking at the IO scheduler level. Given this, fix the issue by removing zone append support and using regular write BIOs for synchronous direct writes. This allows preseving the use of iomap and having identical synchronous and asynchronous sequential file write path. Zone append support will be reintroduced later through io_uring commands to ensure that the needed special handling is done correctly. Reported-by: Shin'ichiro Kawasaki Fixes: 16d7fd3cfa72 ("zonefs: use iomap for synchronous direct writes") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Tested-by: Shin'ichiro Kawasaki Reviewed-by: Christoph Hellwig --- fs/zonefs/file.c | 111 ++--------------------------------------------------- fs/zonefs/super.c | 9 +---- fs/zonefs/zonefs.h | 2 - 3 files changed, 4 insertions(+), 118 deletions(-) diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c index 92c9aaae3663..789cfb74c146 100644 --- a/fs/zonefs/file.c +++ b/fs/zonefs/file.c @@ -341,77 +341,6 @@ static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence) return generic_file_llseek_size(file, offset, whence, isize, isize); } -struct zonefs_zone_append_bio { - /* The target inode of the BIO */ - struct inode *inode; - - /* For sync writes, the target append write offset */ - u64 append_offset; - - /* - * This member must come last, bio_alloc_bioset will allocate enough - * bytes for entire zonefs_bio but relies on bio being last. - */ - struct bio bio; -}; - -static inline struct zonefs_zone_append_bio * -zonefs_zone_append_bio(struct bio *bio) -{ - return container_of(bio, struct zonefs_zone_append_bio, bio); -} - -static void zonefs_file_zone_append_dio_bio_end_io(struct bio *bio) -{ - struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio); - struct zonefs_zone *z = zonefs_inode_zone(za_bio->inode); - sector_t za_sector; - - if (bio->bi_status != BLK_STS_OK) - goto bio_end; - - /* - * If the file zone was written underneath the file system, the zone - * append operation can still succedd (if the zone is not full) but - * the write append location will not be where we expect it to be. - * Check that we wrote where we intended to, that is, at z->z_wpoffset. - */ - za_sector = z->z_sector + (za_bio->append_offset >> SECTOR_SHIFT); - if (bio->bi_iter.bi_sector != za_sector) { - zonefs_warn(za_bio->inode->i_sb, - "Invalid write sector %llu for zone at %llu\n", - bio->bi_iter.bi_sector, z->z_sector); - bio->bi_status = BLK_STS_IOERR; - } - -bio_end: - iomap_dio_bio_end_io(bio); -} - -static void zonefs_file_zone_append_dio_submit_io(const struct iomap_iter *iter, - struct bio *bio, - loff_t file_offset) -{ - struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio); - struct inode *inode = iter->inode; - struct zonefs_zone *z = zonefs_inode_zone(inode); - - /* - * Issue a zone append BIO to process sync dio writes. The append - * file offset is saved to check the zone append write location - * on completion of the BIO. - */ - za_bio->inode = inode; - za_bio->append_offset = file_offset; - - bio->bi_opf &= ~REQ_OP_WRITE; - bio->bi_opf |= REQ_OP_ZONE_APPEND; - bio->bi_iter.bi_sector = z->z_sector; - bio->bi_end_io = zonefs_file_zone_append_dio_bio_end_io; - - submit_bio(bio); -} - static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size, int error, unsigned int flags) { @@ -442,14 +371,6 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size, return 0; } -static struct bio_set zonefs_zone_append_bio_set; - -static const struct iomap_dio_ops zonefs_zone_append_dio_ops = { - .submit_io = zonefs_file_zone_append_dio_submit_io, - .end_io = zonefs_file_write_dio_end_io, - .bio_set = &zonefs_zone_append_bio_set, -}; - static const struct iomap_dio_ops zonefs_write_dio_ops = { .end_io = zonefs_file_write_dio_end_io, }; @@ -533,9 +454,6 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) struct zonefs_inode_info *zi = ZONEFS_I(inode); struct zonefs_zone *z = zonefs_inode_zone(inode); struct super_block *sb = inode->i_sb; - const struct iomap_dio_ops *dio_ops; - bool sync = is_sync_kiocb(iocb); - bool append = false; ssize_t ret, count; /* @@ -543,7 +461,8 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) * as this can cause write reordering (e.g. the first aio gets EAGAIN * on the inode lock but the second goes through but is now unaligned). */ - if (zonefs_zone_is_seq(z) && !sync && (iocb->ki_flags & IOCB_NOWAIT)) + if (zonefs_zone_is_seq(z) && !is_sync_kiocb(iocb) && + (iocb->ki_flags & IOCB_NOWAIT)) return -EOPNOTSUPP; if (iocb->ki_flags & IOCB_NOWAIT) { @@ -573,18 +492,6 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) goto inode_unlock; } mutex_unlock(&zi->i_truncate_mutex); - append = sync; - } - - if (append) { - unsigned int max = bdev_max_zone_append_sectors(sb->s_bdev); - - max = ALIGN_DOWN(max << SECTOR_SHIFT, sb->s_blocksize); - iov_iter_truncate(from, max); - - dio_ops = &zonefs_zone_append_dio_ops; - } else { - dio_ops = &zonefs_write_dio_ops; } /* @@ -593,7 +500,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) * the user can make sense of the error. */ ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops, - dio_ops, 0, NULL, 0); + &zonefs_write_dio_ops, 0, NULL, 0); if (ret == -ENOTBLK) ret = -EBUSY; @@ -938,15 +845,3 @@ const struct file_operations zonefs_file_operations = { .splice_write = iter_file_splice_write, .iopoll = iocb_bio_iopoll, }; - -int zonefs_file_bioset_init(void) -{ - return bioset_init(&zonefs_zone_append_bio_set, BIO_POOL_SIZE, - offsetof(struct zonefs_zone_append_bio, bio), - BIOSET_NEED_BVECS); -} - -void zonefs_file_bioset_exit(void) -{ - bioset_exit(&zonefs_zone_append_bio_set); -} diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index bbe44a26a8e5..9350221abfc5 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -1412,13 +1412,9 @@ static int __init zonefs_init(void) BUILD_BUG_ON(sizeof(struct zonefs_super) != ZONEFS_SUPER_SIZE); - ret = zonefs_file_bioset_init(); - if (ret) - return ret; - ret = zonefs_init_inodecache(); if (ret) - goto destroy_bioset; + return ret; ret = zonefs_sysfs_init(); if (ret) @@ -1434,8 +1430,6 @@ sysfs_exit: zonefs_sysfs_exit(); destroy_inodecache: zonefs_destroy_inodecache(); -destroy_bioset: - zonefs_file_bioset_exit(); return ret; } @@ -1445,7 +1439,6 @@ static void __exit zonefs_exit(void) unregister_filesystem(&zonefs_type); zonefs_sysfs_exit(); zonefs_destroy_inodecache(); - zonefs_file_bioset_exit(); } MODULE_AUTHOR("Damien Le Moal"); diff --git a/fs/zonefs/zonefs.h b/fs/zonefs/zonefs.h index f663b8ebc2cb..8175652241b5 100644 --- a/fs/zonefs/zonefs.h +++ b/fs/zonefs/zonefs.h @@ -279,8 +279,6 @@ extern const struct file_operations zonefs_dir_operations; extern const struct address_space_operations zonefs_file_aops; extern const struct file_operations zonefs_file_operations; int zonefs_file_truncate(struct inode *inode, loff_t isize); -int zonefs_file_bioset_init(void); -void zonefs_file_bioset_exit(void); /* In sysfs.c */ int zonefs_sysfs_register(struct super_block *sb); -- cgit v1.2.3 From 56b930dcd88c2adc261410501c402c790980bdb5 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Mon, 7 Aug 2023 19:20:03 +0200 Subject: hwmon: (aquacomputer_d5next) Add selective 200ms delay after sending ctrl report Add a 200ms delay after sending a ctrl report to Quadro, Octo, D5 Next and Aquaero to give them enough time to process the request and save the data to memory. Otherwise, under heavier userspace loads where multiple sysfs entries are usually set in quick succession, a new ctrl report could be requested from the device while it's still processing the previous one and fail with -EPIPE. The delay is only applied if two ctrl report operations are near each other in time. Reported by a user on Github [1] and tested by both of us. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/82 Fixes: 752b927951ea ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Octo") Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230807172004.456968-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index a997dbcb563f..023807859be7 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -13,9 +13,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -63,6 +65,8 @@ static const char *const aqc_device_names[] = { #define CTRL_REPORT_ID 0x03 #define AQUAERO_CTRL_REPORT_ID 0x0b +#define CTRL_REPORT_DELAY 200 /* ms */ + /* The HID report that the official software always sends * after writing values, currently same for all devices */ @@ -527,6 +531,9 @@ struct aqc_data { int secondary_ctrl_report_size; u8 *secondary_ctrl_report; + ktime_t last_ctrl_report_op; + int ctrl_report_delay; /* Delay between two ctrl report operations, in ms */ + int buffer_size; u8 *buffer; int checksum_start; @@ -611,17 +618,35 @@ static int aqc_aquastreamxt_convert_fan_rpm(u16 val) return 0; } +static void aqc_delay_ctrl_report(struct aqc_data *priv) +{ + /* + * If previous read or write is too close to this one, delay the current operation + * to give the device enough time to process the previous one. + */ + if (priv->ctrl_report_delay) { + s64 delta = ktime_ms_delta(ktime_get(), priv->last_ctrl_report_op); + + if (delta < priv->ctrl_report_delay) + msleep(priv->ctrl_report_delay - delta); + } +} + /* Expects the mutex to be locked */ static int aqc_get_ctrl_data(struct aqc_data *priv) { int ret; + aqc_delay_ctrl_report(priv); + memset(priv->buffer, 0x00, priv->buffer_size); ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) ret = -ENODATA; + priv->last_ctrl_report_op = ktime_get(); + return ret; } @@ -631,6 +656,8 @@ static int aqc_send_ctrl_data(struct aqc_data *priv) int ret; u16 checksum; + aqc_delay_ctrl_report(priv); + /* Checksum is not needed for Aquaero */ if (priv->kind != aquaero) { /* Init and xorout value for CRC-16/USB is 0xffff */ @@ -646,12 +673,16 @@ static int aqc_send_ctrl_data(struct aqc_data *priv) ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret < 0) - return ret; + goto record_access_and_ret; /* The official software sends this report after every change, so do it here as well */ ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id, priv->secondary_ctrl_report, priv->secondary_ctrl_report_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + +record_access_and_ret: + priv->last_ctrl_report_op = ktime_get(); + return ret; } @@ -1524,6 +1555,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE; priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET; + priv->ctrl_report_delay = CTRL_REPORT_DELAY; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -1547,6 +1579,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET; priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; + priv->ctrl_report_delay = CTRL_REPORT_DELAY; priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; @@ -1597,6 +1630,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET; priv->buffer_size = OCTO_CTRL_REPORT_SIZE; + priv->ctrl_report_delay = CTRL_REPORT_DELAY; priv->power_cycle_count_offset = OCTO_POWER_CYCLES; @@ -1624,6 +1658,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; + priv->ctrl_report_delay = CTRL_REPORT_DELAY; priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET; priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; -- cgit v1.2.3 From 5f68718b34a531a556f2f50300ead2862278da26 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 9 Aug 2023 14:31:54 +0200 Subject: netfilter: nf_tables: GC transaction API to avoid race with control plane The set types rhashtable and rbtree use a GC worker to reclaim memory. From system work queue, in periodic intervals, a scan of the table is done. The major caveat here is that the nft transaction mutex is not held. This causes a race between control plane and GC when they attempt to delete the same element. We cannot grab the netlink mutex from the work queue, because the control plane has to wait for the GC work queue in case the set is to be removed, so we get following deadlock: cpu 1 cpu2 GC work transaction comes in , lock nft mutex `acquire nft mutex // BLOCKS transaction asks to remove the set set destruction calls cancel_work_sync() cancel_work_sync will now block forever, because it is waiting for the mutex the caller already owns. This patch adds a new API that deals with garbage collection in two steps: 1) Lockless GC of expired elements sets on the NFT_SET_ELEM_DEAD_BIT so they are not visible via lookup. Annotate current GC sequence in the GC transaction. Enqueue GC transaction work as soon as it is full. If ruleset is updated, then GC transaction is aborted and retried later. 2) GC work grabs the mutex. If GC sequence has changed then this GC transaction lost race with control plane, abort it as it contains stale references to objects and let GC try again later. If the ruleset is intact, then this GC transaction deactivates and removes the elements and it uses call_rcu() to destroy elements. Note that no elements are removed from GC lockless path, the _DEAD bit is set and pointers are collected. GC catchall does not remove the elements anymore too. There is a new set->dead flag that is set on to abort the GC transaction to deal with set->ops->destroy() path which removes the remaining elements in the set from commit_release, where no mutex is held. To deal with GC when mutex is held, which allows safe deactivate and removal, add sync GC API which releases the set element object via call_rcu(). This is used by rbtree and pipapo backends which also perform garbage collection from control plane path. Since element removal from sets can happen from control plane and element garbage collection/timeout, it is necessary to keep the set structure alive until all elements have been deactivated and destroyed. We cannot do a cancel_work_sync or flush_work in nft_set_destroy because its called with the transaction mutex held, but the aforementioned async work queue might be blocked on the very mutex that nft_set_destroy() callchain is sitting on. This gives us the choice of ABBA deadlock or UaF. To avoid both, add set->refs refcount_t member. The GC API can then increment the set refcount and release it once the elements have been free'd. Set backends are adapted to use the GC transaction API in a follow up patch entitled: ("netfilter: nf_tables: use gc transaction API in set backends") This is joint work with Florian Westphal. Fixes: cfed7e1b1f8e ("netfilter: nf_tables: add set garbage collection helpers") Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 64 +++++++++- net/netfilter/nf_tables_api.c | 248 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 300 insertions(+), 12 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 640441a2f926..7256e9c80477 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -512,6 +512,7 @@ struct nft_set_elem_expr { * * @list: table set list node * @bindings: list of set bindings + * @refs: internal refcounting for async set destruction * @table: table this set belongs to * @net: netnamespace this set belongs to * @name: name of the set @@ -541,6 +542,7 @@ struct nft_set_elem_expr { struct nft_set { struct list_head list; struct list_head bindings; + refcount_t refs; struct nft_table *table; possible_net_t net; char *name; @@ -562,7 +564,8 @@ struct nft_set { struct list_head pending_update; /* runtime data below here */ const struct nft_set_ops *ops ____cacheline_aligned; - u16 flags:14, + u16 flags:13, + dead:1, genmask:2; u8 klen; u8 dlen; @@ -1592,6 +1595,32 @@ static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext) clear_bit(NFT_SET_ELEM_BUSY_BIT, word); } +#define NFT_SET_ELEM_DEAD_MASK (1 << 3) + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define NFT_SET_ELEM_DEAD_BIT 3 +#elif defined(__BIG_ENDIAN_BITFIELD) +#define NFT_SET_ELEM_DEAD_BIT (BITS_PER_LONG - BITS_PER_BYTE + 3) +#else +#error +#endif + +static inline void nft_set_elem_dead(struct nft_set_ext *ext) +{ + unsigned long *word = (unsigned long *)ext; + + BUILD_BUG_ON(offsetof(struct nft_set_ext, genmask) != 0); + set_bit(NFT_SET_ELEM_DEAD_BIT, word); +} + +static inline int nft_set_elem_is_dead(const struct nft_set_ext *ext) +{ + unsigned long *word = (unsigned long *)ext; + + BUILD_BUG_ON(offsetof(struct nft_set_ext, genmask) != 0); + return test_bit(NFT_SET_ELEM_DEAD_BIT, word); +} + /** * struct nft_trans - nf_tables object update in transaction * @@ -1732,6 +1761,38 @@ struct nft_trans_flowtable { #define nft_trans_flowtable_flags(trans) \ (((struct nft_trans_flowtable *)trans->data)->flags) +#define NFT_TRANS_GC_BATCHCOUNT 256 + +struct nft_trans_gc { + struct list_head list; + struct net *net; + struct nft_set *set; + u32 seq; + u8 count; + void *priv[NFT_TRANS_GC_BATCHCOUNT]; + struct rcu_head rcu; +}; + +struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set, + unsigned int gc_seq, gfp_t gfp); +void nft_trans_gc_destroy(struct nft_trans_gc *trans); + +struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc, + unsigned int gc_seq, gfp_t gfp); +void nft_trans_gc_queue_async_done(struct nft_trans_gc *gc); + +struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp); +void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans); + +void nft_trans_gc_elem_add(struct nft_trans_gc *gc, void *priv); + +struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc, + unsigned int gc_seq); + +void nft_setelem_data_deactivate(const struct net *net, + const struct nft_set *set, + struct nft_set_elem *elem); + int __init nft_chain_filter_init(void); void nft_chain_filter_fini(void); @@ -1758,6 +1819,7 @@ struct nftables_pernet { struct mutex commit_mutex; u64 table_handle; unsigned int base_seq; + unsigned int gc_seq; }; extern unsigned int nf_tables_net_id; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index b4321869e5c6..c28bacb9479b 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -31,7 +31,9 @@ static LIST_HEAD(nf_tables_expressions); static LIST_HEAD(nf_tables_objects); static LIST_HEAD(nf_tables_flowtables); static LIST_HEAD(nf_tables_destroy_list); +static LIST_HEAD(nf_tables_gc_list); static DEFINE_SPINLOCK(nf_tables_destroy_list_lock); +static DEFINE_SPINLOCK(nf_tables_gc_list_lock); enum { NFT_VALIDATE_SKIP = 0, @@ -120,6 +122,9 @@ static void nft_validate_state_update(struct nft_table *table, u8 new_validate_s static void nf_tables_trans_destroy_work(struct work_struct *w); static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work); +static void nft_trans_gc_work(struct work_struct *work); +static DECLARE_WORK(trans_gc_work, nft_trans_gc_work); + static void nft_ctx_init(struct nft_ctx *ctx, struct net *net, const struct sk_buff *skb, @@ -582,10 +587,6 @@ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type, return __nft_trans_set_add(ctx, msg_type, set, NULL); } -static void nft_setelem_data_deactivate(const struct net *net, - const struct nft_set *set, - struct nft_set_elem *elem); - static int nft_mapelem_deactivate(const struct nft_ctx *ctx, struct nft_set *set, const struct nft_set_iter *iter, @@ -5055,6 +5056,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, INIT_LIST_HEAD(&set->bindings); INIT_LIST_HEAD(&set->catchall_list); + refcount_set(&set->refs, 1); set->table = table; write_pnet(&set->net, net); set->ops = ops; @@ -5122,6 +5124,14 @@ static void nft_set_catchall_destroy(const struct nft_ctx *ctx, } } +static void nft_set_put(struct nft_set *set) +{ + if (refcount_dec_and_test(&set->refs)) { + kfree(set->name); + kvfree(set); + } +} + static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) { int i; @@ -5134,8 +5144,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) set->ops->destroy(ctx, set); nft_set_catchall_destroy(ctx, set); - kfree(set->name); - kvfree(set); + nft_set_put(set); } static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info, @@ -6278,7 +6287,8 @@ struct nft_set_ext *nft_set_catchall_lookup(const struct net *net, list_for_each_entry_rcu(catchall, &set->catchall_list, list) { ext = nft_set_elem_ext(set, catchall->elem); if (nft_set_elem_active(ext, genmask) && - !nft_set_elem_expired(ext)) + !nft_set_elem_expired(ext) && + !nft_set_elem_is_dead(ext)) return ext; } @@ -6933,9 +6943,9 @@ static void nft_setelem_data_activate(const struct net *net, nft_use_inc_restore(&(*nft_set_ext_obj(ext))->use); } -static void nft_setelem_data_deactivate(const struct net *net, - const struct nft_set *set, - struct nft_set_elem *elem) +void nft_setelem_data_deactivate(const struct net *net, + const struct nft_set *set, + struct nft_set_elem *elem) { const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); @@ -9418,6 +9428,207 @@ void nft_chain_del(struct nft_chain *chain) list_del_rcu(&chain->list); } +static void nft_trans_gc_setelem_remove(struct nft_ctx *ctx, + struct nft_trans_gc *trans) +{ + void **priv = trans->priv; + unsigned int i; + + for (i = 0; i < trans->count; i++) { + struct nft_set_elem elem = { + .priv = priv[i], + }; + + nft_setelem_data_deactivate(ctx->net, trans->set, &elem); + nft_setelem_remove(ctx->net, trans->set, &elem); + } +} + +void nft_trans_gc_destroy(struct nft_trans_gc *trans) +{ + nft_set_put(trans->set); + put_net(trans->net); + kfree(trans); +} + +static void nft_trans_gc_trans_free(struct rcu_head *rcu) +{ + struct nft_set_elem elem = {}; + struct nft_trans_gc *trans; + struct nft_ctx ctx = {}; + unsigned int i; + + trans = container_of(rcu, struct nft_trans_gc, rcu); + ctx.net = read_pnet(&trans->set->net); + + for (i = 0; i < trans->count; i++) { + elem.priv = trans->priv[i]; + if (!nft_setelem_is_catchall(trans->set, &elem)) + atomic_dec(&trans->set->nelems); + + nf_tables_set_elem_destroy(&ctx, trans->set, elem.priv); + } + + nft_trans_gc_destroy(trans); +} + +static bool nft_trans_gc_work_done(struct nft_trans_gc *trans) +{ + struct nftables_pernet *nft_net; + struct nft_ctx ctx = {}; + + nft_net = nft_pernet(trans->net); + + mutex_lock(&nft_net->commit_mutex); + + /* Check for race with transaction, otherwise this batch refers to + * stale objects that might not be there anymore. Skip transaction if + * set has been destroyed from control plane transaction in case gc + * worker loses race. + */ + if (READ_ONCE(nft_net->gc_seq) != trans->seq || trans->set->dead) { + mutex_unlock(&nft_net->commit_mutex); + return false; + } + + ctx.net = trans->net; + ctx.table = trans->set->table; + + nft_trans_gc_setelem_remove(&ctx, trans); + mutex_unlock(&nft_net->commit_mutex); + + return true; +} + +static void nft_trans_gc_work(struct work_struct *work) +{ + struct nft_trans_gc *trans, *next; + LIST_HEAD(trans_gc_list); + + spin_lock(&nf_tables_destroy_list_lock); + list_splice_init(&nf_tables_gc_list, &trans_gc_list); + spin_unlock(&nf_tables_destroy_list_lock); + + list_for_each_entry_safe(trans, next, &trans_gc_list, list) { + list_del(&trans->list); + if (!nft_trans_gc_work_done(trans)) { + nft_trans_gc_destroy(trans); + continue; + } + call_rcu(&trans->rcu, nft_trans_gc_trans_free); + } +} + +struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set, + unsigned int gc_seq, gfp_t gfp) +{ + struct net *net = read_pnet(&set->net); + struct nft_trans_gc *trans; + + trans = kzalloc(sizeof(*trans), gfp); + if (!trans) + return NULL; + + refcount_inc(&set->refs); + trans->set = set; + trans->net = get_net(net); + trans->seq = gc_seq; + + return trans; +} + +void nft_trans_gc_elem_add(struct nft_trans_gc *trans, void *priv) +{ + trans->priv[trans->count++] = priv; +} + +static void nft_trans_gc_queue_work(struct nft_trans_gc *trans) +{ + spin_lock(&nf_tables_gc_list_lock); + list_add_tail(&trans->list, &nf_tables_gc_list); + spin_unlock(&nf_tables_gc_list_lock); + + schedule_work(&trans_gc_work); +} + +static int nft_trans_gc_space(struct nft_trans_gc *trans) +{ + return NFT_TRANS_GC_BATCHCOUNT - trans->count; +} + +struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc, + unsigned int gc_seq, gfp_t gfp) +{ + if (nft_trans_gc_space(gc)) + return gc; + + nft_trans_gc_queue_work(gc); + + return nft_trans_gc_alloc(gc->set, gc_seq, gfp); +} + +void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans) +{ + if (trans->count == 0) { + nft_trans_gc_destroy(trans); + return; + } + + nft_trans_gc_queue_work(trans); +} + +struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp) +{ + if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net))) + return NULL; + + if (nft_trans_gc_space(gc)) + return gc; + + call_rcu(&gc->rcu, nft_trans_gc_trans_free); + + return nft_trans_gc_alloc(gc->set, 0, gfp); +} + +void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans) +{ + WARN_ON_ONCE(!lockdep_commit_lock_is_held(trans->net)); + + if (trans->count == 0) { + nft_trans_gc_destroy(trans); + return; + } + + call_rcu(&trans->rcu, nft_trans_gc_trans_free); +} + +struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc, + unsigned int gc_seq) +{ + struct nft_set_elem_catchall *catchall; + const struct nft_set *set = gc->set; + struct nft_set_ext *ext; + + list_for_each_entry_rcu(catchall, &set->catchall_list, list) { + ext = nft_set_elem_ext(set, catchall->elem); + + if (!nft_set_elem_expired(ext)) + continue; + if (nft_set_elem_is_dead(ext)) + goto dead_elem; + + nft_set_elem_dead(ext); +dead_elem: + gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC); + if (!gc) + return NULL; + + nft_trans_gc_elem_add(gc, catchall->elem); + } + + return gc; +} + static void nf_tables_module_autoload_cleanup(struct net *net) { struct nftables_pernet *nft_net = nft_pernet(net); @@ -9580,11 +9791,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) { struct nftables_pernet *nft_net = nft_pernet(net); struct nft_trans *trans, *next; + unsigned int base_seq, gc_seq; LIST_HEAD(set_update_list); struct nft_trans_elem *te; struct nft_chain *chain; struct nft_table *table; - unsigned int base_seq; LIST_HEAD(adl); int err; @@ -9661,6 +9872,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) WRITE_ONCE(nft_net->base_seq, base_seq); + /* Bump gc counter, it becomes odd, this is the busy mark. */ + gc_seq = READ_ONCE(nft_net->gc_seq); + WRITE_ONCE(nft_net->gc_seq, ++gc_seq); + /* step 3. Start new generation, rules_gen_X now in use. */ net->nft.gencursor = nft_gencursor_next(net); @@ -9768,6 +9983,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) break; case NFT_MSG_DELSET: case NFT_MSG_DESTROYSET: + nft_trans_set(trans)->dead = 1; list_del_rcu(&nft_trans_set(trans)->list); nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), trans->msg_type, GFP_KERNEL); @@ -9870,6 +10086,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) nft_commit_notify(net, NETLINK_CB(skb).portid); nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); nf_tables_commit_audit_log(&adl, nft_net->base_seq); + + WRITE_ONCE(nft_net->gc_seq, ++gc_seq); nf_tables_commit_release(net); return 0; @@ -10919,6 +11137,7 @@ static int __net_init nf_tables_init_net(struct net *net) INIT_LIST_HEAD(&nft_net->notify_list); mutex_init(&nft_net->commit_mutex); nft_net->base_seq = 1; + nft_net->gc_seq = 0; return 0; } @@ -10947,10 +11166,16 @@ static void __net_exit nf_tables_exit_net(struct net *net) WARN_ON_ONCE(!list_empty(&nft_net->notify_list)); } +static void nf_tables_exit_batch(struct list_head *net_exit_list) +{ + flush_work(&trans_gc_work); +} + static struct pernet_operations nf_tables_net_ops = { .init = nf_tables_init_net, .pre_exit = nf_tables_pre_exit_net, .exit = nf_tables_exit_net, + .exit_batch = nf_tables_exit_batch, .id = &nf_tables_net_id, .size = sizeof(struct nftables_pernet), }; @@ -11022,6 +11247,7 @@ static void __exit nf_tables_module_exit(void) nft_chain_filter_fini(); nft_chain_route_fini(); unregister_pernet_subsys(&nf_tables_net_ops); + cancel_work_sync(&trans_gc_work); cancel_work_sync(&trans_destroy_work); rcu_barrier(); rhltable_destroy(&nft_objname_ht); -- cgit v1.2.3 From f6c383b8c31a93752a52697f8430a71dcbc46adf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 9 Aug 2023 14:54:23 +0200 Subject: netfilter: nf_tables: adapt set backend to use GC transaction API Use the GC transaction API to replace the old and buggy gc API and the busy mark approach. No set elements are removed from async garbage collection anymore, instead the _DEAD bit is set on so the set element is not visible from lookup path anymore. Async GC enqueues transaction work that might be aborted and retried later. rbtree and pipapo set backends does not set on the _DEAD bit from the sync GC path since this runs in control plane path where mutex is held. In this case, set elements are deactivated, removed and then released via RCU callback, sync GC never fails. Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges") Fixes: 8d8540c4f5e0 ("netfilter: nft_set_rbtree: add timeout support") Fixes: 9d0982927e79 ("netfilter: nft_hash: add support for timeouts") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 7 +- net/netfilter/nft_set_hash.c | 77 +++++++++++++--------- net/netfilter/nft_set_pipapo.c | 48 ++++++++++---- net/netfilter/nft_set_rbtree.c | 144 +++++++++++++++++++++++++---------------- 4 files changed, 173 insertions(+), 103 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index c28bacb9479b..fd4b5da7ac3c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6380,7 +6380,6 @@ static void nft_setelem_activate(struct net *net, struct nft_set *set, if (nft_setelem_is_catchall(set, elem)) { nft_set_elem_change_active(net, set, ext); - nft_set_elem_clear_busy(ext); } else { set->ops->activate(net, set, elem); } @@ -6395,8 +6394,7 @@ static int nft_setelem_catchall_deactivate(const struct net *net, list_for_each_entry(catchall, &set->catchall_list, list) { ext = nft_set_elem_ext(set, catchall->elem); - if (!nft_is_active(net, ext) || - nft_set_elem_mark_busy(ext)) + if (!nft_is_active(net, ext)) continue; kfree(elem->priv); @@ -7109,8 +7107,7 @@ static int nft_set_catchall_flush(const struct nft_ctx *ctx, list_for_each_entry_rcu(catchall, &set->catchall_list, list) { ext = nft_set_elem_ext(set, catchall->elem); - if (!nft_set_elem_active(ext, genmask) || - nft_set_elem_mark_busy(ext)) + if (!nft_set_elem_active(ext, genmask)) continue; elem.priv = catchall->elem; diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 24caa31fa231..2f067e4596b0 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -59,6 +59,8 @@ static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg, if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen)) return 1; + if (nft_set_elem_is_dead(&he->ext)) + return 1; if (nft_set_elem_expired(&he->ext)) return 1; if (!nft_set_elem_active(&he->ext, x->genmask)) @@ -188,7 +190,6 @@ static void nft_rhash_activate(const struct net *net, const struct nft_set *set, struct nft_rhash_elem *he = elem->priv; nft_set_elem_change_active(net, set, &he->ext); - nft_set_elem_clear_busy(&he->ext); } static bool nft_rhash_flush(const struct net *net, @@ -196,12 +197,9 @@ static bool nft_rhash_flush(const struct net *net, { struct nft_rhash_elem *he = priv; - if (!nft_set_elem_mark_busy(&he->ext) || - !nft_is_active(net, &he->ext)) { - nft_set_elem_change_active(net, set, &he->ext); - return true; - } - return false; + nft_set_elem_change_active(net, set, &he->ext); + + return true; } static void *nft_rhash_deactivate(const struct net *net, @@ -218,9 +216,8 @@ static void *nft_rhash_deactivate(const struct net *net, rcu_read_lock(); he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); - if (he != NULL && - !nft_rhash_flush(net, set, he)) - he = NULL; + if (he) + nft_set_elem_change_active(net, set, &he->ext); rcu_read_unlock(); @@ -312,25 +309,48 @@ static bool nft_rhash_expr_needs_gc_run(const struct nft_set *set, static void nft_rhash_gc(struct work_struct *work) { + struct nftables_pernet *nft_net; struct nft_set *set; struct nft_rhash_elem *he; struct nft_rhash *priv; - struct nft_set_gc_batch *gcb = NULL; struct rhashtable_iter hti; + struct nft_trans_gc *gc; + struct net *net; + u32 gc_seq; priv = container_of(work, struct nft_rhash, gc_work.work); set = nft_set_container_of(priv); + net = read_pnet(&set->net); + nft_net = nft_pernet(net); + gc_seq = READ_ONCE(nft_net->gc_seq); + + gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL); + if (!gc) + goto done; rhashtable_walk_enter(&priv->ht, &hti); rhashtable_walk_start(&hti); while ((he = rhashtable_walk_next(&hti))) { if (IS_ERR(he)) { - if (PTR_ERR(he) != -EAGAIN) - break; + if (PTR_ERR(he) != -EAGAIN) { + nft_trans_gc_destroy(gc); + gc = NULL; + goto try_later; + } continue; } + /* Ruleset has been updated, try later. */ + if (READ_ONCE(nft_net->gc_seq) != gc_seq) { + nft_trans_gc_destroy(gc); + gc = NULL; + goto try_later; + } + + if (nft_set_elem_is_dead(&he->ext)) + goto dead_elem; + if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPRESSIONS) && nft_rhash_expr_needs_gc_run(set, &he->ext)) goto needs_gc_run; @@ -338,26 +358,26 @@ static void nft_rhash_gc(struct work_struct *work) if (!nft_set_elem_expired(&he->ext)) continue; needs_gc_run: - if (nft_set_elem_mark_busy(&he->ext)) - continue; + nft_set_elem_dead(&he->ext); +dead_elem: + gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC); + if (!gc) + goto try_later; - gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); - if (gcb == NULL) - break; - rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params); - atomic_dec(&set->nelems); - nft_set_gc_batch_add(gcb, he); + nft_trans_gc_elem_add(gc, he); } + + gc = nft_trans_gc_catchall(gc, gc_seq); + +try_later: + /* catchall list iteration requires rcu read side lock. */ rhashtable_walk_stop(&hti); rhashtable_walk_exit(&hti); - he = nft_set_catchall_gc(set); - if (he) { - gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); - if (gcb) - nft_set_gc_batch_add(gcb, he); - } - nft_set_gc_batch_complete(gcb); + if (gc) + nft_trans_gc_queue_async_done(gc); + +done: queue_delayed_work(system_power_efficient_wq, &priv->gc_work, nft_set_gc_interval(set)); } @@ -420,7 +440,6 @@ static void nft_rhash_destroy(const struct nft_ctx *ctx, }; cancel_delayed_work_sync(&priv->gc_work); - rcu_barrier(); rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy, (void *)&rhash_ctx); } diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index d54784ea465b..a5b8301afe4a 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -1536,16 +1536,34 @@ static void pipapo_drop(struct nft_pipapo_match *m, } } +static void nft_pipapo_gc_deactivate(struct net *net, struct nft_set *set, + struct nft_pipapo_elem *e) + +{ + struct nft_set_elem elem = { + .priv = e, + }; + + nft_setelem_data_deactivate(net, set, &elem); +} + /** * pipapo_gc() - Drop expired entries from set, destroy start and end elements * @set: nftables API set representation * @m: Matching data */ -static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m) +static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m) { + struct nft_set *set = (struct nft_set *) _set; struct nft_pipapo *priv = nft_set_priv(set); + struct net *net = read_pnet(&set->net); int rules_f0, first_rule = 0; struct nft_pipapo_elem *e; + struct nft_trans_gc *gc; + + gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); + if (!gc) + return; while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) { union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS]; @@ -1569,13 +1587,20 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m) f--; i--; e = f->mt[rulemap[i].to].e; - if (nft_set_elem_expired(&e->ext) && - !nft_set_elem_mark_busy(&e->ext)) { + + /* synchronous gc never fails, there is no need to set on + * NFT_SET_ELEM_DEAD_BIT. + */ + if (nft_set_elem_expired(&e->ext)) { priv->dirty = true; - pipapo_drop(m, rulemap); - rcu_barrier(); - nft_set_elem_destroy(set, e, true); + gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); + if (!gc) + break; + + nft_pipapo_gc_deactivate(net, set, e); + pipapo_drop(m, rulemap); + nft_trans_gc_elem_add(gc, e); /* And check again current first rule, which is now the * first we haven't checked. @@ -1585,11 +1610,11 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m) } } - e = nft_set_catchall_gc(set); - if (e) - nft_set_elem_destroy(set, e, true); - - priv->last_gc = jiffies; + gc = nft_trans_gc_catchall(gc, 0); + if (gc) { + nft_trans_gc_queue_sync_done(gc); + priv->last_gc = jiffies; + } } /** @@ -1714,7 +1739,6 @@ static void nft_pipapo_activate(const struct net *net, return; nft_set_elem_change_active(net, set, &e->ext); - nft_set_elem_clear_busy(&e->ext); } /** diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index 39956e5341c9..f9d4c8fcbbf8 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -46,6 +46,12 @@ static int nft_rbtree_cmp(const struct nft_set *set, set->klen); } +static bool nft_rbtree_elem_expired(const struct nft_rbtree_elem *rbe) +{ + return nft_set_elem_expired(&rbe->ext) || + nft_set_elem_is_dead(&rbe->ext); +} + static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set, const u32 *key, const struct nft_set_ext **ext, unsigned int seq) @@ -80,7 +86,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set continue; } - if (nft_set_elem_expired(&rbe->ext)) + if (nft_rbtree_elem_expired(rbe)) return false; if (nft_rbtree_interval_end(rbe)) { @@ -98,7 +104,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set if (set->flags & NFT_SET_INTERVAL && interval != NULL && nft_set_elem_active(&interval->ext, genmask) && - !nft_set_elem_expired(&interval->ext) && + !nft_rbtree_elem_expired(interval) && nft_rbtree_interval_start(interval)) { *ext = &interval->ext; return true; @@ -215,6 +221,18 @@ static void *nft_rbtree_get(const struct net *net, const struct nft_set *set, return rbe; } +static void nft_rbtree_gc_remove(struct net *net, struct nft_set *set, + struct nft_rbtree *priv, + struct nft_rbtree_elem *rbe) +{ + struct nft_set_elem elem = { + .priv = rbe, + }; + + nft_setelem_data_deactivate(net, set, &elem); + rb_erase(&rbe->node, &priv->root); +} + static int nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, struct nft_rbtree_elem *rbe, @@ -222,11 +240,12 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set, { struct nft_set *set = (struct nft_set *)__set; struct rb_node *prev = rb_prev(&rbe->node); + struct net *net = read_pnet(&set->net); struct nft_rbtree_elem *rbe_prev; - struct nft_set_gc_batch *gcb; + struct nft_trans_gc *gc; - gcb = nft_set_gc_batch_check(set, NULL, GFP_ATOMIC); - if (!gcb) + gc = nft_trans_gc_alloc(set, 0, GFP_ATOMIC); + if (!gc) return -ENOMEM; /* search for end interval coming before this element. @@ -244,17 +263,28 @@ static int nft_rbtree_gc_elem(const struct nft_set *__set, if (prev) { rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node); + nft_rbtree_gc_remove(net, set, priv, rbe_prev); - rb_erase(&rbe_prev->node, &priv->root); - atomic_dec(&set->nelems); - nft_set_gc_batch_add(gcb, rbe_prev); + /* There is always room in this trans gc for this element, + * memory allocation never actually happens, hence, the warning + * splat in such case. No need to set NFT_SET_ELEM_DEAD_BIT, + * this is synchronous gc which never fails. + */ + gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); + if (WARN_ON_ONCE(!gc)) + return -ENOMEM; + + nft_trans_gc_elem_add(gc, rbe_prev); } - rb_erase(&rbe->node, &priv->root); - atomic_dec(&set->nelems); + nft_rbtree_gc_remove(net, set, priv, rbe); + gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); + if (WARN_ON_ONCE(!gc)) + return -ENOMEM; + + nft_trans_gc_elem_add(gc, rbe); - nft_set_gc_batch_add(gcb, rbe); - nft_set_gc_batch_complete(gcb); + nft_trans_gc_queue_sync_done(gc); return 0; } @@ -482,7 +512,6 @@ static void nft_rbtree_activate(const struct net *net, struct nft_rbtree_elem *rbe = elem->priv; nft_set_elem_change_active(net, set, &rbe->ext); - nft_set_elem_clear_busy(&rbe->ext); } static bool nft_rbtree_flush(const struct net *net, @@ -490,12 +519,9 @@ static bool nft_rbtree_flush(const struct net *net, { struct nft_rbtree_elem *rbe = priv; - if (!nft_set_elem_mark_busy(&rbe->ext) || - !nft_is_active(net, &rbe->ext)) { - nft_set_elem_change_active(net, set, &rbe->ext); - return true; - } - return false; + nft_set_elem_change_active(net, set, &rbe->ext); + + return true; } static void *nft_rbtree_deactivate(const struct net *net, @@ -570,26 +596,40 @@ cont: static void nft_rbtree_gc(struct work_struct *work) { - struct nft_rbtree_elem *rbe, *rbe_end = NULL, *rbe_prev = NULL; - struct nft_set_gc_batch *gcb = NULL; + struct nft_rbtree_elem *rbe, *rbe_end = NULL; + struct nftables_pernet *nft_net; struct nft_rbtree *priv; + struct nft_trans_gc *gc; struct rb_node *node; struct nft_set *set; + unsigned int gc_seq; struct net *net; - u8 genmask; priv = container_of(work, struct nft_rbtree, gc_work.work); set = nft_set_container_of(priv); net = read_pnet(&set->net); - genmask = nft_genmask_cur(net); + nft_net = nft_pernet(net); + gc_seq = READ_ONCE(nft_net->gc_seq); + + gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL); + if (!gc) + goto done; write_lock_bh(&priv->lock); write_seqcount_begin(&priv->count); for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { + + /* Ruleset has been updated, try later. */ + if (READ_ONCE(nft_net->gc_seq) != gc_seq) { + nft_trans_gc_destroy(gc); + gc = NULL; + goto try_later; + } + rbe = rb_entry(node, struct nft_rbtree_elem, node); - if (!nft_set_elem_active(&rbe->ext, genmask)) - continue; + if (nft_set_elem_is_dead(&rbe->ext)) + goto dead_elem; /* elements are reversed in the rbtree for historical reasons, * from highest to lowest value, that is why end element is @@ -602,46 +642,36 @@ static void nft_rbtree_gc(struct work_struct *work) if (!nft_set_elem_expired(&rbe->ext)) continue; - if (nft_set_elem_mark_busy(&rbe->ext)) { - rbe_end = NULL; + nft_set_elem_dead(&rbe->ext); + + if (!rbe_end) continue; - } - if (rbe_prev) { - rb_erase(&rbe_prev->node, &priv->root); - rbe_prev = NULL; - } - gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); - if (!gcb) - break; + nft_set_elem_dead(&rbe_end->ext); - atomic_dec(&set->nelems); - nft_set_gc_batch_add(gcb, rbe); - rbe_prev = rbe; + gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC); + if (!gc) + goto try_later; - if (rbe_end) { - atomic_dec(&set->nelems); - nft_set_gc_batch_add(gcb, rbe_end); - rb_erase(&rbe_end->node, &priv->root); - rbe_end = NULL; - } - node = rb_next(node); - if (!node) - break; + nft_trans_gc_elem_add(gc, rbe_end); + rbe_end = NULL; +dead_elem: + gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC); + if (!gc) + goto try_later; + + nft_trans_gc_elem_add(gc, rbe); } - if (rbe_prev) - rb_erase(&rbe_prev->node, &priv->root); + + gc = nft_trans_gc_catchall(gc, gc_seq); + +try_later: write_seqcount_end(&priv->count); write_unlock_bh(&priv->lock); - rbe = nft_set_catchall_gc(set); - if (rbe) { - gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); - if (gcb) - nft_set_gc_batch_add(gcb, rbe); - } - nft_set_gc_batch_complete(gcb); - + if (gc) + nft_trans_gc_queue_async_done(gc); +done: queue_delayed_work(system_power_efficient_wq, &priv->gc_work, nft_set_gc_interval(set)); } -- cgit v1.2.3 From c92db3030492b8ad1d0faace7a93bbcf53850d0c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 9 Aug 2023 15:00:06 +0200 Subject: netfilter: nft_set_hash: mark set element as dead when deleting from packet path Set on the NFT_SET_ELEM_DEAD_BIT flag on this element, instead of performing element removal which might race with an ongoing transaction. Enable gc when dynamic flag is set on since dynset deletion requires garbage collection after this patch. Fixes: d0a8d877da97 ("netfilter: nft_dynset: support for element deletion") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_set_hash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 2f067e4596b0..cef5df846000 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -249,7 +249,9 @@ static bool nft_rhash_delete(const struct nft_set *set, if (he == NULL) return false; - return rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params) == 0; + nft_set_elem_dead(&he->ext); + + return true; } static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set, @@ -412,7 +414,7 @@ static int nft_rhash_init(const struct nft_set *set, return err; INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc); - if (set->flags & NFT_SET_TIMEOUT) + if (set->flags & (NFT_SET_TIMEOUT | NFT_SET_EVAL)) nft_rhash_gc_init(set); return 0; -- cgit v1.2.3 From a2dd0233cbc4d8a0abb5f64487487ffc9265beb5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 9 Aug 2023 15:00:36 +0200 Subject: netfilter: nf_tables: remove busy mark and gc batch API Ditch it, it has been replace it by the GC transaction API and it has no clients anymore. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 98 ++------------------------------------- net/netfilter/nf_tables_api.c | 48 +------------------ 2 files changed, 4 insertions(+), 142 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 7256e9c80477..35870858ddf2 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -599,7 +599,6 @@ struct nft_set *nft_set_lookup_global(const struct net *net, struct nft_set_ext *nft_set_catchall_lookup(const struct net *net, const struct nft_set *set); -void *nft_set_catchall_gc(const struct nft_set *set); static inline unsigned long nft_set_gc_interval(const struct nft_set *set) { @@ -816,62 +815,6 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem, void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, const struct nft_set *set, void *elem); -/** - * struct nft_set_gc_batch_head - nf_tables set garbage collection batch - * - * @rcu: rcu head - * @set: set the elements belong to - * @cnt: count of elements - */ -struct nft_set_gc_batch_head { - struct rcu_head rcu; - const struct nft_set *set; - unsigned int cnt; -}; - -#define NFT_SET_GC_BATCH_SIZE ((PAGE_SIZE - \ - sizeof(struct nft_set_gc_batch_head)) / \ - sizeof(void *)) - -/** - * struct nft_set_gc_batch - nf_tables set garbage collection batch - * - * @head: GC batch head - * @elems: garbage collection elements - */ -struct nft_set_gc_batch { - struct nft_set_gc_batch_head head; - void *elems[NFT_SET_GC_BATCH_SIZE]; -}; - -struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set, - gfp_t gfp); -void nft_set_gc_batch_release(struct rcu_head *rcu); - -static inline void nft_set_gc_batch_complete(struct nft_set_gc_batch *gcb) -{ - if (gcb != NULL) - call_rcu(&gcb->head.rcu, nft_set_gc_batch_release); -} - -static inline struct nft_set_gc_batch * -nft_set_gc_batch_check(const struct nft_set *set, struct nft_set_gc_batch *gcb, - gfp_t gfp) -{ - if (gcb != NULL) { - if (gcb->head.cnt + 1 < ARRAY_SIZE(gcb->elems)) - return gcb; - nft_set_gc_batch_complete(gcb); - } - return nft_set_gc_batch_alloc(set, gfp); -} - -static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb, - void *elem) -{ - gcb->elems[gcb->head.cnt++] = elem; -} - struct nft_expr_ops; /** * struct nft_expr_type - nf_tables expression type @@ -1560,47 +1503,12 @@ static inline void nft_set_elem_change_active(const struct net *net, #endif /* IS_ENABLED(CONFIG_NF_TABLES) */ -/* - * We use a free bit in the genmask field to indicate the element - * is busy, meaning it is currently being processed either by - * the netlink API or GC. - * - * Even though the genmask is only a single byte wide, this works - * because the extension structure if fully constant once initialized, - * so there are no non-atomic write accesses unless it is already - * marked busy. - */ -#define NFT_SET_ELEM_BUSY_MASK (1 << 2) - -#if defined(__LITTLE_ENDIAN_BITFIELD) -#define NFT_SET_ELEM_BUSY_BIT 2 -#elif defined(__BIG_ENDIAN_BITFIELD) -#define NFT_SET_ELEM_BUSY_BIT (BITS_PER_LONG - BITS_PER_BYTE + 2) -#else -#error -#endif - -static inline int nft_set_elem_mark_busy(struct nft_set_ext *ext) -{ - unsigned long *word = (unsigned long *)ext; - - BUILD_BUG_ON(offsetof(struct nft_set_ext, genmask) != 0); - return test_and_set_bit(NFT_SET_ELEM_BUSY_BIT, word); -} - -static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext) -{ - unsigned long *word = (unsigned long *)ext; - - clear_bit(NFT_SET_ELEM_BUSY_BIT, word); -} - -#define NFT_SET_ELEM_DEAD_MASK (1 << 3) +#define NFT_SET_ELEM_DEAD_MASK (1 << 2) #if defined(__LITTLE_ENDIAN_BITFIELD) -#define NFT_SET_ELEM_DEAD_BIT 3 +#define NFT_SET_ELEM_DEAD_BIT 2 #elif defined(__BIG_ENDIAN_BITFIELD) -#define NFT_SET_ELEM_DEAD_BIT (BITS_PER_LONG - BITS_PER_BYTE + 3) +#define NFT_SET_ELEM_DEAD_BIT (BITS_PER_LONG - BITS_PER_BYTE + 2) #else #error #endif diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index fd4b5da7ac3c..c62227ae7746 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6296,29 +6296,6 @@ struct nft_set_ext *nft_set_catchall_lookup(const struct net *net, } EXPORT_SYMBOL_GPL(nft_set_catchall_lookup); -void *nft_set_catchall_gc(const struct nft_set *set) -{ - struct nft_set_elem_catchall *catchall, *next; - struct nft_set_ext *ext; - void *elem = NULL; - - list_for_each_entry_safe(catchall, next, &set->catchall_list, list) { - ext = nft_set_elem_ext(set, catchall->elem); - - if (!nft_set_elem_expired(ext) || - nft_set_elem_mark_busy(ext)) - continue; - - elem = catchall->elem; - list_del_rcu(&catchall->list); - kfree_rcu(catchall, rcu); - break; - } - - return elem; -} -EXPORT_SYMBOL_GPL(nft_set_catchall_gc); - static int nft_setelem_catchall_insert(const struct net *net, struct nft_set *set, const struct nft_set_elem *elem, @@ -6789,7 +6766,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, goto err_elem_free; } - ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; + ext->genmask = nft_genmask_cur(ctx->net); err = nft_setelem_insert(ctx->net, set, &elem, &ext2, flags); if (err) { @@ -7181,29 +7158,6 @@ static int nf_tables_delsetelem(struct sk_buff *skb, return err; } -void nft_set_gc_batch_release(struct rcu_head *rcu) -{ - struct nft_set_gc_batch *gcb; - unsigned int i; - - gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu); - for (i = 0; i < gcb->head.cnt; i++) - nft_set_elem_destroy(gcb->head.set, gcb->elems[i], true); - kfree(gcb); -} - -struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set, - gfp_t gfp) -{ - struct nft_set_gc_batch *gcb; - - gcb = kzalloc(sizeof(*gcb), gfp); - if (gcb == NULL) - return gcb; - gcb->head.set = set; - return gcb; -} - /* * Stateful objects */ -- cgit v1.2.3 From 07dd476f6116966cb2006e25fdcf48f0715115ff Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 24 Jul 2023 13:26:10 +0200 Subject: drm/shmem-helper: Reset vma->vm_ops before calling dma_buf_mmap() The dma-buf backend is supposed to provide its own vm_ops, but some implementation just have nothing special to do and leave vm_ops untouched, probably expecting this field to be zero initialized (this is the case with the system_heap implementation for instance). Let's reset vma->vm_ops to NULL to keep things working with these implementations. Fixes: 26d3ac3cb04d ("drm/shmem-helpers: Redirect mmap for imported dma-buf") Cc: Cc: Daniel Vetter Reported-by: Roman Stratiienko Signed-off-by: Boris Brezillon Tested-by: Roman Stratiienko Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20230724112610.60974-1-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_gem_shmem_helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 4ea6507a77e5..baaf0e0feb06 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -623,7 +623,13 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct int ret; if (obj->import_attach) { + /* Reset both vm_ops and vm_private_data, so we don't end up with + * vm_ops pointing to our implementation if the dma-buf backend + * doesn't set those fields. + */ vma->vm_private_data = NULL; + vma->vm_ops = NULL; + ret = dma_buf_mmap(obj->dma_buf, vma, 0); /* Drop the reference drm_gem_mmap_obj() acquired.*/ -- cgit v1.2.3 From 182ac87070e26d32a01445cec7ca7afa07411468 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sat, 29 Jul 2023 16:53:02 +0200 Subject: Documentation/hw-vuln: Unify filename specification in index Most of the index.rst files in Documentation/ refer to other rst files without their file extension in the name. Do that here too. No functional changes. Reported-by: Linus Torvalds Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230809102700.29449-2-bp@alien8.de --- Documentation/admin-guide/hw-vuln/index.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst index a7d37e124831..de99caabf65a 100644 --- a/Documentation/admin-guide/hw-vuln/index.rst +++ b/Documentation/admin-guide/hw-vuln/index.rst @@ -13,11 +13,11 @@ are configurable at compile, boot or run time. l1tf mds tsx_async_abort - multihit.rst - special-register-buffer-data-sampling.rst - core-scheduling.rst - l1d_flush.rst - processor_mmio_stale_data.rst - cross-thread-rsb.rst + multihit + special-register-buffer-data-sampling + core-scheduling + l1d_flush + processor_mmio_stale_data + cross-thread-rsb srso - gather_data_sampling.rst + gather_data_sampling -- cgit v1.2.3 From 0fddfe338210aa018137c03030c581f5ea4be282 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sat, 29 Jul 2023 17:20:33 +0200 Subject: driver core: cpu: Unify redundant silly stubs Make them all a weak function, aliasing to a single function which issues the "Not affected" string. No functional changes. Suggested-by: Linus Torvalds Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Greg Kroah-Hartman Reviewed-by: Nikolay Borisov Link: https://lore.kernel.org/r/20230809102700.29449-3-bp@alien8.de --- drivers/base/cpu.c | 87 ++++++++++++------------------------------------------ 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 52df435eecf8..054c81b65502 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -509,79 +509,30 @@ static void __init cpu_dev_register_generic(void) } #ifdef CONFIG_GENERIC_CPU_VULNERABILITIES - -ssize_t __weak cpu_show_meltdown(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_spectre_v1(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_spectre_v2(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_l1tf(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_mds(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_tsx_async_abort(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_itlb_multihit(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_srbds(struct device *dev, +ssize_t cpu_show_not_affected(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "Not affected\n"); } -ssize_t __weak cpu_show_mmio_stale_data(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_retbleed(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - -ssize_t __weak cpu_show_spec_rstack_overflow(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} +#define CPU_SHOW_VULN_FALLBACK(func) \ + ssize_t cpu_show_##func(struct device *, \ + struct device_attribute *, char *) \ + __attribute__((weak, alias("cpu_show_not_affected"))) + +CPU_SHOW_VULN_FALLBACK(meltdown); +CPU_SHOW_VULN_FALLBACK(spectre_v1); +CPU_SHOW_VULN_FALLBACK(spectre_v2); +CPU_SHOW_VULN_FALLBACK(spec_store_bypass); +CPU_SHOW_VULN_FALLBACK(l1tf); +CPU_SHOW_VULN_FALLBACK(mds); +CPU_SHOW_VULN_FALLBACK(tsx_async_abort); +CPU_SHOW_VULN_FALLBACK(itlb_multihit); +CPU_SHOW_VULN_FALLBACK(srbds); +CPU_SHOW_VULN_FALLBACK(mmio_stale_data); +CPU_SHOW_VULN_FALLBACK(retbleed); +CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); +CPU_SHOW_VULN_FALLBACK(gather_data_sampling); ssize_t __weak cpu_show_gds(struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From 09f9f37c324d90102e8574856ab168c34de1916d Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 2 Aug 2023 20:07:32 +0200 Subject: Documentation/srso: Document IBPB aspect and fix formatting Add a note about the dependency of the User->User mitigation on the previous Spectre v2 IBPB selection. Make the layout moar pretty. Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230809102700.29449-4-bp@alien8.de --- Documentation/admin-guide/hw-vuln/srso.rst | 71 ++++++++++++++++++------------ 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/srso.rst b/Documentation/admin-guide/hw-vuln/srso.rst index 32eb5e6db272..af59a9395662 100644 --- a/Documentation/admin-guide/hw-vuln/srso.rst +++ b/Documentation/admin-guide/hw-vuln/srso.rst @@ -42,42 +42,59 @@ The sysfs file showing SRSO mitigation status is: The possible values in this file are: - - 'Not affected' The processor is not vulnerable + * 'Not affected': - - 'Vulnerable: no microcode' The processor is vulnerable, no - microcode extending IBPB functionality - to address the vulnerability has been - applied. + The processor is not vulnerable - - 'Mitigation: microcode' Extended IBPB functionality microcode - patch has been applied. It does not - address User->Kernel and Guest->Host - transitions protection but it does - address User->User and VM->VM attack - vectors. + * 'Vulnerable: no microcode': - (spec_rstack_overflow=microcode) + The processor is vulnerable, no microcode extending IBPB + functionality to address the vulnerability has been applied. - - 'Mitigation: safe RET' Software-only mitigation. It complements - the extended IBPB microcode patch - functionality by addressing User->Kernel - and Guest->Host transitions protection. + * 'Mitigation: microcode': - Selected by default or by - spec_rstack_overflow=safe-ret + Extended IBPB functionality microcode patch has been applied. It does + not address User->Kernel and Guest->Host transitions protection but it + does address User->User and VM->VM attack vectors. - - 'Mitigation: IBPB' Similar protection as "safe RET" above - but employs an IBPB barrier on privilege - domain crossings (User->Kernel, - Guest->Host). + Note that User->User mitigation is controlled by how the IBPB aspect in + the Spectre v2 mitigation is selected: - (spec_rstack_overflow=ibpb) + * conditional IBPB: + + where each process can select whether it needs an IBPB issued + around it PR_SPEC_DISABLE/_ENABLE etc, see :doc:`spectre` + + * strict: + + i.e., always on - by supplying spectre_v2_user=on on the kernel + command line + + (spec_rstack_overflow=microcode) + + * 'Mitigation: safe RET': + + Software-only mitigation. It complements the extended IBPB microcode + patch functionality by addressing User->Kernel and Guest->Host + transitions protection. + + Selected by default or by spec_rstack_overflow=safe-ret + + * 'Mitigation: IBPB': + + Similar protection as "safe RET" above but employs an IBPB barrier on + privilege domain crossings (User->Kernel, Guest->Host). + + (spec_rstack_overflow=ibpb) + + * 'Mitigation: IBPB on VMEXIT': + + Mitigation addressing the cloud provider scenario - the Guest->Host + transitions only. + + (spec_rstack_overflow=ibpb-vmexit) - - 'Mitigation: IBPB on VMEXIT' Mitigation addressing the cloud provider - scenario - the Guest->Host transitions - only. - (spec_rstack_overflow=ibpb-vmexit) In order to exploit vulnerability, an attacker needs to: -- cgit v1.2.3 From cbe8ded48b939b9d55d2c5589ab56caa7b530709 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 9 Aug 2023 09:40:26 -0700 Subject: x86/srso: Fix build breakage with the LLVM linker The assertion added to verify the difference in bits set of the addresses of srso_untrain_ret_alias() and srso_safe_ret_alias() would fail to link in LLVM's ld.lld linker with the following error: ld.lld: error: ./arch/x86/kernel/vmlinux.lds:210: at least one side of the expression must be absolute ld.lld: error: ./arch/x86/kernel/vmlinux.lds:211: at least one side of the expression must be absolute Use ABSOLUTE to evaluate the expression referring to at least one of the symbols so that LLD can evaluate the linker script. Also, add linker version info to the comment about XOR being unsupported in either ld.bfd or ld.lld until somewhat recently. Fixes: fb3bd914b3ec ("x86/srso: Add a Speculative RAS Overflow mitigation") Closes: https://lore.kernel.org/llvm/CA+G9fYsdUeNu-gwbs0+T6XHi4hYYk=Y9725-wFhZ7gJMspLDRA@mail.gmail.com/ Reported-by: Nathan Chancellor Reported-by: Daniel Kolesa Reported-by: Naresh Kamboju Suggested-by: Sven Volkinsfeld Signed-off-by: Nick Desaulniers Signed-off-by: Borislav Petkov (AMD) Link: https://github.com/ClangBuiltLinux/linux/issues/1907 Link: https://lore.kernel.org/r/20230809-gds-v1-1-eaac90b0cbcc@google.com --- arch/x86/kernel/vmlinux.lds.S | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index e76813230192..ef06211bae4c 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -529,11 +529,17 @@ INIT_PER_CPU(irq_stack_backing_store); #ifdef CONFIG_CPU_SRSO /* - * GNU ld cannot do XOR so do: (A | B) - (A & B) in order to compute the XOR + * GNU ld cannot do XOR until 2.41. + * https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=f6f78318fca803c4907fb8d7f6ded8295f1947b1 + * + * LLVM lld cannot do XOR until lld-17. + * https://github.com/llvm/llvm-project/commit/fae96104d4378166cbe5c875ef8ed808a356f3fb + * + * Instead do: (A | B) - (A & B) in order to compute the XOR * of the two function addresses: */ -. = ASSERT(((srso_untrain_ret_alias | srso_safe_ret_alias) - - (srso_untrain_ret_alias & srso_safe_ret_alias)) == ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 20)), +. = ASSERT(((ABSOLUTE(srso_untrain_ret_alias) | srso_safe_ret_alias) - + (ABSOLUTE(srso_untrain_ret_alias) & srso_safe_ret_alias)) == ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 20)), "SRSO function pair won't alias"); #endif -- cgit v1.2.3 From 6524c798b727ffdb5c7eaed2f50e8e839997df8e Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 10 Aug 2023 13:22:29 +0200 Subject: driver core: cpu: Make cpu_show_not_affected() static Fix a -Wmissing-prototypes warning and add the gather_data_sampling() stub macro call for real. Fixes: 0fddfe338210 ("driver core: cpu: Unify redundant silly stubs") Closes: https://lore.kernel.org/oe-kbuild-all/202308101956.oRj1ls7s-lkp@intel.com Reported-by: kernel test robot Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/202308101956.oRj1ls7s-lkp@intel.com --- drivers/base/cpu.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 054c81b65502..d7300d885822 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -509,7 +509,7 @@ static void __init cpu_dev_register_generic(void) } #ifdef CONFIG_GENERIC_CPU_VULNERABILITIES -ssize_t cpu_show_not_affected(struct device *dev, +static ssize_t cpu_show_not_affected(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "Not affected\n"); @@ -534,12 +534,6 @@ CPU_SHOW_VULN_FALLBACK(retbleed); CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); CPU_SHOW_VULN_FALLBACK(gather_data_sampling); -ssize_t __weak cpu_show_gds(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "Not affected\n"); -} - static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); @@ -552,7 +546,7 @@ static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL); static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL); static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); -static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); +static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gather_data_sampling, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, -- cgit v1.2.3 From fc1f91b9231a28fba333f931a031bf776bc6ef0e Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 21 Jul 2023 16:09:43 -0400 Subject: btrfs: wait for actual caching progress during allocation Recently we've been having mysterious hangs while running generic/475 on the CI system. This turned out to be something like this: Task 1 dmsetup suspend --nolockfs -> __dm_suspend -> dm_wait_for_completion -> dm_wait_for_bios_completion -> Unable to complete because of IO's on a plug in Task 2 Task 2 wb_workfn -> wb_writeback -> blk_start_plug -> writeback_sb_inodes -> Infinite loop unable to make an allocation Task 3 cache_block_group ->read_extent_buffer_pages ->Waiting for IO to complete that can't be submitted because Task 1 suspended the DM device The problem here is that we need Task 2 to be scheduled completely for the blk plug to flush. Normally this would happen, we normally wait for the block group caching to finish (Task 3), and this schedule would result in the block plug flushing. However if there's enough free space available from the current caching to satisfy the allocation we won't actually wait for the caching to complete. This check however just checks that we have enough space, not that we can make the allocation. In this particular case we were trying to allocate 9MiB, and we had 10MiB of free space, but we didn't have 9MiB of contiguous space to allocate, and thus the allocation failed and we looped. We specifically don't cycle through the FFE loop until we stop finding cached block groups because we don't want to allocate new block groups just because we're caching, so we short circuit the normal loop once we hit LOOP_CACHING_WAIT and we found a caching block group. This is normally fine, except in this particular case where the caching thread can't make progress because the DM device has been suspended. Fix this by not only waiting for free space to >= the amount of space we want to allocate, but also that we make some progress in caching from the time we start waiting. This will keep us from busy looping when the caching is taking a while but still theoretically has enough space for us to allocate from, and fixes this particular case by forcing us to actually sleep and wait for forward progress, which will flush the plug. With this fix we're no longer hanging with generic/475. CC: stable@vger.kernel.org # 6.1+ Reviewed-by: Boris Burkov Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/block-group.c | 17 +++++++++++++++-- fs/btrfs/block-group.h | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 63c3b7172ba5..1e4b70f5280d 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -441,13 +441,23 @@ void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache, u64 num_bytes) { struct btrfs_caching_control *caching_ctl; + int progress; caching_ctl = btrfs_get_caching_control(cache); if (!caching_ctl) return; + /* + * We've already failed to allocate from this block group, so even if + * there's enough space in the block group it isn't contiguous enough to + * allow for an allocation, so wait for at least the next wakeup tick, + * or for the thing to be done. + */ + progress = atomic_read(&caching_ctl->progress); + wait_event(caching_ctl->wait, btrfs_block_group_done(cache) || - (cache->free_space_ctl->free_space >= num_bytes)); + (progress != atomic_read(&caching_ctl->progress) && + (cache->free_space_ctl->free_space >= num_bytes))); btrfs_put_caching_control(caching_ctl); } @@ -802,8 +812,10 @@ next: if (total_found > CACHING_CTL_WAKE_UP) { total_found = 0; - if (wakeup) + if (wakeup) { + atomic_inc(&caching_ctl->progress); wake_up(&caching_ctl->wait); + } } } path->slots[0]++; @@ -910,6 +922,7 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait) init_waitqueue_head(&caching_ctl->wait); caching_ctl->block_group = cache; refcount_set(&caching_ctl->count, 2); + atomic_set(&caching_ctl->progress, 0); btrfs_init_work(&caching_ctl->work, caching_thread, NULL, NULL); spin_lock(&cache->lock); diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index aba5dff66c19..74b61e663028 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -90,6 +90,8 @@ struct btrfs_caching_control { wait_queue_head_t wait; struct btrfs_work work; struct btrfs_block_group *block_group; + /* Track progress of caching during allocation. */ + atomic_t progress; refcount_t count; }; -- cgit v1.2.3 From 6870f41033d839fa72195fd2dd37f902b37ea62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 9 Aug 2023 20:50:10 +0200 Subject: dt-bindings: sound: gtm601: Add description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to us to document the channel and sampling rate requirements. Signed-off-by: Guido GĂŒnther Reviewed-by: David Heidelberg Link: https://lore.kernel.org/r/b6e85fdfaa87d7684a120ccedc1e07d8fe87957f.1691606520.git.agx@sigxcpu.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/option,gtm601.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/option,gtm601.yaml b/Documentation/devicetree/bindings/sound/option,gtm601.yaml index 69c2ccc79dc5..ff813d97fc59 100644 --- a/Documentation/devicetree/bindings/sound/option,gtm601.yaml +++ b/Documentation/devicetree/bindings/sound/option,gtm601.yaml @@ -16,10 +16,12 @@ description: > properties: compatible: oneOf: - - items: # 48 kHz stereo + - description: Broadmobi BM818 (48Khz stereo) + items: - const: broadmobi,bm818 - const: option,gtm601 - - const: option,gtm601 # 8 kHz mono + - description: GTM601 (8kHz mono) + const: option,gtm601 '#sound-dai-cells': const: 0 -- cgit v1.2.3 From 927073ee468d9d9f7ef0fe1eb777a673120e7caa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 10 Aug 2023 09:27:45 +0000 Subject: ASoC: rt715: Add software reset in io init Add software reset before setting preset registers to make sure all the registers are the default value before preset. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/4f405c7deb9642e1a8599c5f103b5759@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt715.h | 7 ++++++ 2 files changed, 63 insertions(+) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 79416bb48814..c95f481cd235 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -52,6 +52,60 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg, return ret; } +static int rt715_index_write_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + pr_err("Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} + +static int rt715_index_read_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) + pr_err("Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid, + unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp, orig; + int ret; + + ret = rt715_index_read_nid(regmap, nid, reg, &orig); + if (ret < 0) + return ret; + + tmp = orig & ~mask; + tmp |= val & mask; + + return rt715_index_write_nid(regmap, nid, reg, tmp); +} + +static void rt715_reset(struct regmap *regmap) +{ + regmap_write(regmap, RT715_FUNC_RESET, 0); + rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS, + RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG, + RT715_CLEAR_HIDDEN_REG); +} + + static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, unsigned int addr_l, unsigned int val_h, unsigned int *r_val, unsigned int *l_val) @@ -1040,6 +1094,8 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); + rt715_reset(rt715->regmap); + /* Mute nid=08h/09h */ regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080); regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080); diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 12a0ae656d09..6e37bf64e12f 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -48,6 +48,7 @@ struct rt715_priv { #define RT715_INLINE_CMD 0x55 /* Index (NID:20h) */ +#define RT715_VD_CLEAR_CTRL 0x01 #define RT715_SDW_INPUT_SEL 0x39 #define RT715_EXT_DMIC_CLK_CTRL2 0x54 @@ -71,6 +72,8 @@ struct rt715_priv { #define RT715_READ_HDA_0 0x2015 #define RT715_PRIV_INDEX_W_H 0x7520 #define RT715_PRIV_INDEX_W_L 0x85a0 +#define RT715_PRIV_INDEX_W_H_2 0x7500 +#define RT715_PRIV_INDEX_W_L_2 0x8580 #define RT715_PRIV_DATA_W_H 0x7420 #define RT715_PRIV_DATA_W_L 0x84a0 #define RT715_PRIV_INDEX_R_H 0x9d20 @@ -198,6 +201,10 @@ struct rt715_priv { #define RT715_SET_DMIC4_CONFIG_DEFAULT4\ (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4) +/* vendor register clear ctrl-1 (0x01)(NID:20h) */ +#define RT715_CLEAR_HIDDEN_REG (0x1 << 15) + + #define RT715_MUTE_SFT 7 #define RT715_DIR_IN_SFT 6 #define RT715_DIR_OUT_SFT 7 -- cgit v1.2.3 From 56fec0051a69ace182ca3fba47be9c13038b4e3f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 10 Aug 2023 11:00:11 +0200 Subject: ACPI: resource: Add IRQ override quirk for PCSpecialist Elimina Pro 16 M The PCSpecialist Elimina Pro 16 M laptop model is a Zen laptop which needs to use the MADT IRQ settings override and which does not have an INT_SRC_OVR entry for IRQ 1 in its MADT. So this model needs a DMI quirk to enable the MADT IRQ settings override to fix its keyboard not working. Fixes: a9c4a912b7dc ("ACPI: resource: Remove "Zen" specific match and quirks") Link: https://bugzilla.kernel.org/show_bug.cgi?id=217394#c18 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 8e32dd5776f5..a4d9f149b48d 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -498,6 +498,17 @@ static const struct dmi_system_id maingear_laptop[] = { { } }; +static const struct dmi_system_id pcspecialist_laptop[] = { + { + .ident = "PCSpecialist Elimina Pro 16 M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"), + DMI_MATCH(DMI_PRODUCT_NAME, "Elimina Pro 16 M"), + }, + }, + { } +}; + static const struct dmi_system_id lg_laptop[] = { { .ident = "LG Electronics 17U70P", @@ -523,6 +534,7 @@ static const struct irq_override_cmp override_table[] = { { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, + { pcspecialist_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, }; -- cgit v1.2.3 From effa24f689ce0948f68c754991a445a8d697d3a8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Jul 2023 06:26:53 -0700 Subject: btrfs: don't stop integrity writeback too early extent_write_cache_pages stops writing pages as soon as nr_to_write hits zero. That is the right thing for opportunistic writeback, but incorrect for data integrity writeback, which needs to ensure that no dirty pages are left in the range. Thus only stop the writeback for WB_SYNC_NONE if nr_to_write hits 0. This is a port of write_cache_pages changes in commit 05fe478dd04e ("mm: write_cache_pages integrity fix"). Note that I've only trigger the problem with other changes to the btrfs writeback code, but this condition seems worthwhile fixing anyway. CC: stable@vger.kernel.org # 4.14+ Reviewed-by: Josef Bacik Signed-off-by: Christoph Hellwig Reviewed-by: David Sterba [ updated comment ] Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index a91d5ad27984..c36eb4956f81 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2164,11 +2164,12 @@ retry: } /* - * the filesystem may choose to bump up nr_to_write. + * The filesystem may choose to bump up nr_to_write. * We have to make sure to honor the new nr_to_write - * at any time + * at any time. */ - nr_to_write_done = wbc->nr_to_write <= 0; + nr_to_write_done = (wbc->sync_mode == WB_SYNC_NONE && + wbc->nr_to_write <= 0); } folio_batch_release(&fbatch); cond_resched(); -- cgit v1.2.3 From 5c25699871112853f231e52d51c576d5c759a020 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Jul 2023 06:26:54 -0700 Subject: btrfs: don't wait for writeback on clean pages in extent_write_cache_pages __extent_writepage could have started on more pages than the one it was called for. This happens regularly for zoned file systems, and in theory could happen for compressed I/O if the worker thread was executed very quickly. For such pages extent_write_cache_pages waits for writeback to complete before moving on to the next page, which is highly inefficient as it blocks the flusher thread. Port over the PageDirty check that was added to write_cache_pages in commit 515f4a037fb ("mm: write_cache_pages optimise page cleaning") to fix this. CC: stable@vger.kernel.org # 4.14+ Reviewed-by: Josef Bacik Signed-off-by: Christoph Hellwig Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index c36eb4956f81..ca765d62324f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2145,6 +2145,12 @@ retry: continue; } + if (!folio_test_dirty(folio)) { + /* Someone wrote it for us. */ + folio_unlock(folio); + continue; + } + if (wbc->sync_mode != WB_SYNC_NONE) { if (folio_test_writeback(folio)) submit_write_bio(bio_ctrl, 0); -- cgit v1.2.3 From 12b2d64e591652a2d97dd3afa2b062ca7a4ba352 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Jul 2023 06:26:55 -0700 Subject: btrfs: properly clear end of the unreserved range in cow_file_range When the call to btrfs_reloc_clone_csums in cow_file_range returns an error, we jump to the out_unlock label with the extent_reserved variable set to false. The cleanup at the label will then call extent_clear_unlock_delalloc on the range from start to end. But we've already added cur_alloc_size to start before the jump, so there might no range be left from the newly incremented start to end. Move the check for 'start < end' so that it is reached by also for the !extent_reserved case. CC: stable@vger.kernel.org # 6.1+ Fixes: a315e68f6e8b ("Btrfs: fix invalid attempt to free reserved space on failure to cow range") Reviewed-by: Josef Bacik Signed-off-by: Christoph Hellwig Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 49cef61f6a39..9055e19b01ef 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1654,8 +1654,6 @@ out_unlock: clear_bits, page_ops); start += cur_alloc_size; - if (start >= end) - return ret; } /* @@ -1664,9 +1662,11 @@ out_unlock: * space_info's bytes_may_use counter, reserved in * btrfs_check_data_free_space(). */ - extent_clear_unlock_delalloc(inode, start, end, locked_page, - clear_bits | EXTENT_CLEAR_DATA_RESV, - page_ops); + if (start < end) { + clear_bits |= EXTENT_CLEAR_DATA_RESV; + extent_clear_unlock_delalloc(inode, start, end, locked_page, + clear_bits, page_ops); + } return ret; } -- cgit v1.2.3 From 773e722a98e25caf96f91aced7070c1858250ba2 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 3 Aug 2023 17:20:41 +0800 Subject: btrfs: avoid race between qgroup tree creation and relocation [BUG] Syzbot reported a weird ASSERT() triggered inside prepare_to_merge(). assertion failed: root->reloc_root == reloc_root, in fs/btrfs/relocation.c:1919 ------------[ cut here ]------------ kernel BUG at fs/btrfs/relocation.c:1919! invalid opcode: 0000 [#1] PREEMPT SMP KASAN CPU: 0 PID: 9904 Comm: syz-executor.3 Not tainted 6.4.0-syzkaller-08881-g533925cb7604 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 RIP: 0010:prepare_to_merge+0xbb2/0xc40 fs/btrfs/relocation.c:1919 Code: fe e9 f5 (...) RSP: 0018:ffffc9000325f760 EFLAGS: 00010246 RAX: 000000000000004f RBX: ffff888075644030 RCX: 1481ccc522da5800 RDX: ffffc90005c09000 RSI: 00000000000364ca RDI: 00000000000364cb RBP: ffffc9000325f870 R08: ffffffff816f33ac R09: 1ffff9200064bea0 R10: dffffc0000000000 R11: fffff5200064bea1 R12: ffff888075644000 R13: ffff88803b166000 R14: ffff88803b166560 R15: ffff88803b166558 FS: 00007f4e305fd700(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000056080679c000 CR3: 00000000193ad000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: relocate_block_group+0xa5d/0xcd0 fs/btrfs/relocation.c:3749 btrfs_relocate_block_group+0x7ab/0xd70 fs/btrfs/relocation.c:4087 btrfs_relocate_chunk+0x12c/0x3b0 fs/btrfs/volumes.c:3283 __btrfs_balance+0x1b06/0x2690 fs/btrfs/volumes.c:4018 btrfs_balance+0xbdb/0x1120 fs/btrfs/volumes.c:4402 btrfs_ioctl_balance+0x496/0x7c0 fs/btrfs/ioctl.c:3604 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl+0xf8/0x170 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f4e2f88c389 [CAUSE] With extra debugging, the offending reloc_root is for quota tree (rootid 8). Normally we should not use the reloc tree for quota root at all, as reloc trees are only for subvolume trees. But there is a race between quota enabling and relocation, this happens after commit 85724171b302 ("btrfs: fix the btrfs_get_global_root return value"). Before that commit, for quota and free space tree, we exit immediately if we cannot grab it from fs_info. But now we would try to read it from disk, just as if they are fs trees, this sets ROOT_SHAREABLE flags in such race: Thread A | Thread B ---------------------------------+------------------------------ btrfs_quota_enable() | | | btrfs_get_root_ref() | | |- btrfs_get_global_root() | | | Returned NULL | | |- btrfs_lookup_fs_root() | | | Returned NULL |- btrfs_create_tree() | | | Now quota root item is | | | inserted | |- btrfs_read_tree_root() | | | Got the newly inserted quota root | | |- btrfs_init_fs_root() | | | Set ROOT_SHAREABLE flag [FIX] Get back to the old behavior by returning PTR_ERR(-ENOENT) if the target objectid is not a subvolume tree or data reloc tree. Reported-and-tested-by: syzbot+ae97a827ae1c3336bbb4@syzkaller.appspotmail.com Fixes: 85724171b302 ("btrfs: fix the btrfs_get_global_root return value") Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9b9914e5f03d..11b1ac716f3b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1300,6 +1300,16 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, root = btrfs_get_global_root(fs_info, objectid); if (root) return root; + + /* + * If we're called for non-subvolume trees, and above function didn't + * find one, do not try to read it from disk. + * + * This is namely for free-space-tree and quota tree, which can change + * at runtime and should only be grabbed from fs_info. + */ + if (!is_fstree(objectid) && objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) + return ERR_PTR(-ENOENT); again: root = btrfs_lookup_fs_root(fs_info, objectid); if (root) { -- cgit v1.2.3 From 05d7ce504545f7874529701664c90814ca645c5d Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 3 Aug 2023 17:20:42 +0800 Subject: btrfs: exit gracefully if reloc roots don't match [BUG] Syzbot reported a crash that an ASSERT() got triggered inside prepare_to_merge(). [CAUSE] The root cause of the triggered ASSERT() is we can have a race between quota tree creation and relocation. This leads us to create a duplicated quota tree in the btrfs_read_fs_root() path, and since it's treated as fs tree, it would have ROOT_SHAREABLE flag, causing us to create a reloc tree for it. The bug itself is fixed by a dedicated patch for it, but this already taught us the ASSERT() is not something straightforward for developers. [ENHANCEMENT] Instead of using an ASSERT(), let's handle it gracefully and output extra info about the mismatch reloc roots to help debug. Also with the above ASSERT() removed, we can trigger ASSERT(0)s inside merge_reloc_roots() later. Also replace those ASSERT(0)s with WARN_ON()s. CC: stable@vger.kernel.org # 5.15+ Reported-by: syzbot+ae97a827ae1c3336bbb4@syzkaller.appspotmail.com Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/relocation.c | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 25a3361caedc..46c3c1d57266 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1916,7 +1916,39 @@ again: err = PTR_ERR(root); break; } - ASSERT(root->reloc_root == reloc_root); + + if (unlikely(root->reloc_root != reloc_root)) { + if (root->reloc_root) { + btrfs_err(fs_info, +"reloc tree mismatch, root %lld has reloc root key (%lld %u %llu) gen %llu, expect reloc root key (%lld %u %llu) gen %llu", + root->root_key.objectid, + root->reloc_root->root_key.objectid, + root->reloc_root->root_key.type, + root->reloc_root->root_key.offset, + btrfs_root_generation( + &root->reloc_root->root_item), + reloc_root->root_key.objectid, + reloc_root->root_key.type, + reloc_root->root_key.offset, + btrfs_root_generation( + &reloc_root->root_item)); + } else { + btrfs_err(fs_info, +"reloc tree mismatch, root %lld has no reloc root, expect reloc root key (%lld %u %llu) gen %llu", + root->root_key.objectid, + reloc_root->root_key.objectid, + reloc_root->root_key.type, + reloc_root->root_key.offset, + btrfs_root_generation( + &reloc_root->root_item)); + } + list_add(&reloc_root->root_list, &reloc_roots); + btrfs_put_root(root); + btrfs_abort_transaction(trans, -EUCLEAN); + if (!err) + err = -EUCLEAN; + break; + } /* * set reference count to 1, so btrfs_recover_relocation @@ -1989,7 +2021,7 @@ again: root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false); if (btrfs_root_refs(&reloc_root->root_item) > 0) { - if (IS_ERR(root)) { + if (WARN_ON(IS_ERR(root))) { /* * For recovery we read the fs roots on mount, * and if we didn't find the root then we marked @@ -1998,17 +2030,14 @@ again: * memory. However there's no reason we can't * handle the error properly here just in case. */ - ASSERT(0); ret = PTR_ERR(root); goto out; } - if (root->reloc_root != reloc_root) { + if (WARN_ON(root->reloc_root != reloc_root)) { /* - * This is actually impossible without something - * going really wrong (like weird race condition - * or cosmic rays). + * This can happen if on-disk metadata has some + * corruption, e.g. bad reloc tree key offset. */ - ASSERT(0); ret = -EINVAL; goto out; } -- cgit v1.2.3 From 6ebcd021c92b8e4b904552e4d87283032100796d Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 3 Aug 2023 17:20:43 +0800 Subject: btrfs: reject invalid reloc tree root keys with stack dump [BUG] Syzbot reported a crash that an ASSERT() got triggered inside prepare_to_merge(). That ASSERT() makes sure the reloc tree is properly pointed back by its subvolume tree. [CAUSE] After more debugging output, it turns out we had an invalid reloc tree: BTRFS error (device loop1): reloc tree mismatch, root 8 has no reloc root, expect reloc root key (-8, 132, 8) gen 17 Note the above root key is (TREE_RELOC_OBJECTID, ROOT_ITEM, QUOTA_TREE_OBJECTID), meaning it's a reloc tree for quota tree. But reloc trees can only exist for subvolumes, as for non-subvolume trees, we just COW the involved tree block, no need to create a reloc tree since those tree blocks won't be shared with other trees. Only subvolumes tree can share tree blocks with other trees (thus they have BTRFS_ROOT_SHAREABLE flag). Thus this new debug output proves my previous assumption that corrupted on-disk data can trigger that ASSERT(). [FIX] Besides the dedicated fix and the graceful exit, also let tree-checker to check such root keys, to make sure reloc trees can only exist for subvolumes. CC: stable@vger.kernel.org # 5.15+ Reported-by: syzbot+ae97a827ae1c3336bbb4@syzkaller.appspotmail.com Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 3 ++- fs/btrfs/tree-checker.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 11b1ac716f3b..a9a2c5446c18 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1103,7 +1103,8 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev) btrfs_drew_lock_init(&root->snapshot_lock); if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID && - !btrfs_is_data_reloc_root(root)) { + !btrfs_is_data_reloc_root(root) && + is_fstree(root->root_key.objectid)) { set_bit(BTRFS_ROOT_SHAREABLE, &root->state); btrfs_check_and_init_root_item(&root->root_item); } diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 351ba9e90675..11d81e39ef4e 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -446,6 +446,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key, btrfs_item_key_to_cpu(leaf, &item_key, slot); is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY); + /* + * Bad rootid for reloc trees. + * + * Reloc trees are only for subvolume trees, other trees only need + * to be COWed to be relocated. + */ + if (unlikely(is_root_item && key->objectid == BTRFS_TREE_RELOC_OBJECTID && + !is_fstree(key->offset))) { + generic_err(leaf, slot, + "invalid reloc tree for root %lld, root id is not a subvolume tree", + key->offset); + return -EUCLEAN; + } + /* No such tree id */ if (unlikely(key->objectid == 0)) { if (is_root_item) -- cgit v1.2.3 From 92fb94b69c6accf1e49fff699640fa0ce03dc910 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 2 Aug 2023 09:20:24 -0400 Subject: btrfs: set cache_block_group_error if we find an error We set cache_block_group_error if btrfs_cache_block_group() returns an error, this is because we could end up not finding space to allocate and mistakenly return -ENOSPC, and which could then abort the transaction with the incorrect errno, and in the case of ENOSPC result in a WARN_ON() that will trip up tests like generic/475. However there's the case where multiple threads can be racing, one thread gets the proper error, and the other thread doesn't actually call btrfs_cache_block_group(), it instead sees ->cached == BTRFS_CACHE_ERROR. Again the result is the same, we fail to allocate our space and return -ENOSPC. Instead we need to set cache_block_group_error to -EIO in this case to make sure that if we do not make our allocation we get the appropriate error returned back to the caller. CC: stable@vger.kernel.org # 4.14+ Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 911908ea5f6f..f396a9afa403 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4310,8 +4310,11 @@ have_block_group: ret = 0; } - if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) + if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) { + if (!cache_block_group_error) + cache_block_group_error = -EIO; goto loop; + } if (!find_free_extent_check_size_class(ffe_ctl, block_group)) goto loop; -- cgit v1.2.3 From a0f4b7879f2e14986200747d1b545e5daac8c624 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 9 Aug 2023 09:21:58 +0200 Subject: parisc: Fix lightweight spinlock checks to not break futexes The lightweight spinlock checks verify that a spinlock has either value 0 (spinlock locked) and that not any other bits than in __ARCH_SPIN_LOCK_UNLOCKED_VAL is set. This breaks the current LWS code, which writes the address of the lock into the lock word to unlock it, which was an optimization to save one assembler instruction. Fix it by making spinlock_types.h accessible for asm code, change the LWS spinlock-unlocking code to write __ARCH_SPIN_LOCK_UNLOCKED_VAL into the lock word, and add some missing lightweight spinlock checks to the LWS path. Finally, make the spinlock checks dependend on DEBUG_KERNEL. Noticed-by: John David Anglin Signed-off-by: Helge Deller Tested-by: John David Anglin Cc: stable@vger.kernel.org # v6.4+ Fixes: 15e64ef6520e ("parisc: Add lightweight spinlock checks") --- arch/parisc/Kconfig.debug | 2 +- arch/parisc/include/asm/spinlock.h | 2 -- arch/parisc/include/asm/spinlock_types.h | 6 ++++++ arch/parisc/kernel/syscall.S | 23 ++++++++++++++++++++--- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug index 1401e4c5fe5f..bf2b21b96f0b 100644 --- a/arch/parisc/Kconfig.debug +++ b/arch/parisc/Kconfig.debug @@ -2,7 +2,7 @@ # config LIGHTWEIGHT_SPINLOCK_CHECK bool "Enable lightweight spinlock checks" - depends on SMP && !DEBUG_SPINLOCK + depends on DEBUG_KERNEL && SMP && !DEBUG_SPINLOCK default y help Add checks with low performance impact to the spinlock functions diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index edfcb9858bcb..0b326e52255e 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -7,8 +7,6 @@ #include #include -#define SPINLOCK_BREAK_INSN 0x0000c006 /* break 6,6 */ - static inline void arch_spin_val_check(int lock_val) { if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)) diff --git a/arch/parisc/include/asm/spinlock_types.h b/arch/parisc/include/asm/spinlock_types.h index d65934079ebd..efd06a897c6a 100644 --- a/arch/parisc/include/asm/spinlock_types.h +++ b/arch/parisc/include/asm/spinlock_types.h @@ -4,6 +4,10 @@ #define __ARCH_SPIN_LOCK_UNLOCKED_VAL 0x1a46 +#define SPINLOCK_BREAK_INSN 0x0000c006 /* break 6,6 */ + +#ifndef __ASSEMBLY__ + typedef struct { #ifdef CONFIG_PA20 volatile unsigned int slock; @@ -27,6 +31,8 @@ typedef struct { volatile unsigned int counter; } arch_rwlock_t; +#endif /* __ASSEMBLY__ */ + #define __ARCH_RW_LOCK_UNLOCKED__ 0x01000000 #define __ARCH_RW_LOCK_UNLOCKED { .lock_mutex = __ARCH_SPIN_LOCK_UNLOCKED, \ .counter = __ARCH_RW_LOCK_UNLOCKED__ } diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 1373e5129868..1f51aa9c8230 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -39,6 +39,7 @@ registers). #include #include #include +#include #include @@ -66,6 +67,16 @@ registers). stw \reg1, 0(%sr2,\reg2) .endm + /* raise exception if spinlock content is not zero or + * __ARCH_SPIN_LOCK_UNLOCKED_VAL */ + .macro spinlock_check spin_val,tmpreg +#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK + ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmpreg + andcm,= \spin_val, \tmpreg, %r0 + .word SPINLOCK_BREAK_INSN +#endif + .endm + .text .import syscall_exit,code @@ -508,7 +519,8 @@ lws_start: lws_exit_noerror: lws_pagefault_enable %r1,%r21 - stw,ma %r20, 0(%sr2,%r20) + ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21 + stw,ma %r21, 0(%sr2,%r20) ssm PSW_SM_I, %r0 b lws_exit copy %r0, %r21 @@ -521,7 +533,8 @@ lws_wouldblock: lws_pagefault: lws_pagefault_enable %r1,%r21 - stw,ma %r20, 0(%sr2,%r20) + ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21 + stw,ma %r21, 0(%sr2,%r20) ssm PSW_SM_I, %r0 ldo 3(%r0),%r28 b lws_exit @@ -619,6 +632,7 @@ lws_compare_and_swap: /* Try to acquire the lock */ LDCW 0(%sr2,%r20), %r28 + spinlock_check %r28, %r21 comclr,<> %r0, %r28, %r0 b,n lws_wouldblock @@ -772,6 +786,7 @@ cas2_lock_start: /* Try to acquire the lock */ LDCW 0(%sr2,%r20), %r28 + spinlock_check %r28, %r21 comclr,<> %r0, %r28, %r0 b,n lws_wouldblock @@ -1001,6 +1016,7 @@ atomic_xchg_start: /* Try to acquire the lock */ LDCW 0(%sr2,%r20), %r28 + spinlock_check %r28, %r21 comclr,<> %r0, %r28, %r0 b,n lws_wouldblock @@ -1199,6 +1215,7 @@ atomic_store_start: /* Try to acquire the lock */ LDCW 0(%sr2,%r20), %r28 + spinlock_check %r28, %r21 comclr,<> %r0, %r28, %r0 b,n lws_wouldblock @@ -1330,7 +1347,7 @@ ENTRY(lws_lock_start) /* lws locks */ .rept 256 /* Keep locks aligned at 16-bytes */ - .word 1 + .word __ARCH_SPIN_LOCK_UNLOCKED_VAL .word 0 .word 0 .word 0 -- cgit v1.2.3 From 56cf894effc2946f273f7bfc9a28f3741978156c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 9 Aug 2023 17:19:53 +0800 Subject: parisc: pdt: Use PTR_ERR_OR_ZERO() to simplify code Return PTR_ERR_OR_ZERO() instead of return 0 or PTR_ERR() to simplify code. Signed-off-by: Yang Yingliang Signed-off-by: Helge Deller --- arch/parisc/kernel/pdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/parisc/kernel/pdt.c b/arch/parisc/kernel/pdt.c index 0d24735bd918..0f9b3b5914cf 100644 --- a/arch/parisc/kernel/pdt.c +++ b/arch/parisc/kernel/pdt.c @@ -354,10 +354,8 @@ static int __init pdt_initcall(void) return -ENODEV; kpdtd_task = kthread_run(pdt_mainloop, NULL, "kpdtd"); - if (IS_ERR(kpdtd_task)) - return PTR_ERR(kpdtd_task); - return 0; + return PTR_ERR_OR_ZERO(kpdtd_task); } late_initcall(pdt_initcall); -- cgit v1.2.3 From aa1bb8b6351a81b28b9e10ab3414c21ded7cf11d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 03:31:18 +0200 Subject: parisc: fault: Use C99 arrary initializers Sparse wants C99 array initializers. Signed-off-by: Helge Deller --- arch/parisc/mm/fault.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index a4c7c7630f48..2fe5b44986e0 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -192,31 +192,31 @@ int fixup_exception(struct pt_regs *regs) * For implementation see handle_interruption() in traps.c */ static const char * const trap_description[] = { - [1] "High-priority machine check (HPMC)", - [2] "Power failure interrupt", - [3] "Recovery counter trap", - [5] "Low-priority machine check", - [6] "Instruction TLB miss fault", - [7] "Instruction access rights / protection trap", - [8] "Illegal instruction trap", - [9] "Break instruction trap", - [10] "Privileged operation trap", - [11] "Privileged register trap", - [12] "Overflow trap", - [13] "Conditional trap", - [14] "FP Assist Exception trap", - [15] "Data TLB miss fault", - [16] "Non-access ITLB miss fault", - [17] "Non-access DTLB miss fault", - [18] "Data memory protection/unaligned access trap", - [19] "Data memory break trap", - [20] "TLB dirty bit trap", - [21] "Page reference trap", - [22] "Assist emulation trap", - [25] "Taken branch trap", - [26] "Data memory access rights trap", - [27] "Data memory protection ID trap", - [28] "Unaligned data reference trap", + [1] = "High-priority machine check (HPMC)", + [2] = "Power failure interrupt", + [3] = "Recovery counter trap", + [5] = "Low-priority machine check", + [6] = "Instruction TLB miss fault", + [7] = "Instruction access rights / protection trap", + [8] = "Illegal instruction trap", + [9] = "Break instruction trap", + [10] = "Privileged operation trap", + [11] = "Privileged register trap", + [12] = "Overflow trap", + [13] = "Conditional trap", + [14] = "FP Assist Exception trap", + [15] = "Data TLB miss fault", + [16] = "Non-access ITLB miss fault", + [17] = "Non-access DTLB miss fault", + [18] = "Data memory protection/unaligned access trap", + [19] = "Data memory break trap", + [20] = "TLB dirty bit trap", + [21] = "Page reference trap", + [22] = "Assist emulation trap", + [25] = "Taken branch trap", + [26] = "Data memory access rights trap", + [27] = "Data memory protection ID trap", + [28] = "Unaligned data reference trap", }; const char *trap_name(unsigned long code) -- cgit v1.2.3 From b873bde58578db2201b2f30ca708dcb0e35ff4b1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 03:55:47 +0200 Subject: parisc: ioremap: Fix sparse warnings Fix sparse warning: incorrect type in assignment (different base types) expected unsigned long [usertype] addr got void *addr Signed-off-by: Helge Deller --- arch/parisc/mm/ioremap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 345ff0b66499..d7ee1f43d997 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -27,7 +27,7 @@ */ void __iomem *ioremap(unsigned long phys_addr, unsigned long size) { - void __iomem *addr; + uintptr_t addr; struct vm_struct *area; unsigned long offset, last_addr; pgprot_t pgprot; @@ -79,10 +79,9 @@ void __iomem *ioremap(unsigned long phys_addr, unsigned long size) if (!area) return NULL; - addr = (void __iomem *) area->addr; - if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, - phys_addr, pgprot)) { - vunmap(addr); + addr = (uintptr_t) area->addr; + if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) { + vunmap(area->addr); return NULL; } -- cgit v1.2.3 From dc54a52a8cd43cff4fbe8d761c98edeb857d3ad7 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 04:07:01 +0200 Subject: parisc: signal: Fix sparse incorrect type in assignment warning Signed-off-by: Helge Deller --- arch/parisc/kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index f886ff0c75df..e8d27def6c52 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -423,7 +423,7 @@ static void check_syscallno_in_delay_branch(struct pt_regs *regs) regs->gr[31] -= 8; /* delayed branching */ /* Get assembler opcode of code in delay branch */ - uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4); + uaddr = (u32 __user *) ((regs->gr[31] & ~3) + 4); err = get_user(opcode, uaddr); if (err) return; -- cgit v1.2.3 From a07c03e8064026d55d1699d161c536cc437d58d6 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 04:29:29 +0200 Subject: parisc: firmware: Fix sparse context imbalance warnings Tell sparse about correct context for pdc_cpu_rendezvous_*lock() functions. Signed-off-by: Helge Deller --- arch/parisc/kernel/firmware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 6d1c781eb1db..9cd8af5e79d7 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -334,7 +334,7 @@ int __pdc_cpu_rendezvous(void) /** * pdc_cpu_rendezvous_lock - Lock PDC while transitioning to rendezvous state */ -void pdc_cpu_rendezvous_lock(void) +void pdc_cpu_rendezvous_lock(void) __acquires(&pdc_lock) { spin_lock(&pdc_lock); } @@ -342,7 +342,7 @@ void pdc_cpu_rendezvous_lock(void) /** * pdc_cpu_rendezvous_unlock - Unlock PDC after reaching rendezvous state */ -void pdc_cpu_rendezvous_unlock(void) +void pdc_cpu_rendezvous_unlock(void) __releases(&pdc_lock) { spin_unlock(&pdc_lock); } -- cgit v1.2.3 From eed869aaf1305444434ad5a9a56abc45aacc0c40 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 04:34:58 +0200 Subject: parisc: firmware: Mark pdc_result buffers local This fixes a sparse warning which suggest to make those static. Signed-off-by: Helge Deller --- arch/parisc/kernel/firmware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 9cd8af5e79d7..8f37e75f2fb9 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -74,8 +74,8 @@ static DEFINE_SPINLOCK(pdc_lock); #endif -unsigned long pdc_result[NUM_PDC_RESULT] __aligned(8); -unsigned long pdc_result2[NUM_PDC_RESULT] __aligned(8); +static unsigned long pdc_result[NUM_PDC_RESULT] __aligned(8); +static unsigned long pdc_result2[NUM_PDC_RESULT] __aligned(8); #ifdef CONFIG_64BIT #define WIDE_FIRMWARE 0x1 -- cgit v1.2.3 From d566bea4a638ff0ae824df804bc08818bace41a5 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Tue, 8 Aug 2023 15:07:09 +0200 Subject: riscv: Do not allow vmap pud mappings for 3-level page table The vmalloc_fault() path was removed and to avoid syncing the vmalloc PGD mappings, they are now preallocated. But if the kernel can use a PUD mapping (which in sv39 is actually a PGD mapping) for large vmalloc allocation, it will free the current unused preallocated PGD mapping and install a new leaf one. Since there is no sync anymore, some page tables lack this new mapping and that triggers a panic. So only allow PUD mappings for sv48 and sv57. Fixes: 7d3332be011e ("riscv: mm: Pre-allocate PGD entries for vmalloc/modules area") Signed-off-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230808130709.1502614-1-alexghiti@rivosinc.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/vmalloc.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/vmalloc.h b/arch/riscv/include/asm/vmalloc.h index 58d3e447f191..924d01b56c9a 100644 --- a/arch/riscv/include/asm/vmalloc.h +++ b/arch/riscv/include/asm/vmalloc.h @@ -3,12 +3,14 @@ #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP +extern bool pgtable_l4_enabled, pgtable_l5_enabled; + #define IOREMAP_MAX_ORDER (PUD_SHIFT) #define arch_vmap_pud_supported arch_vmap_pud_supported static inline bool arch_vmap_pud_supported(pgprot_t prot) { - return true; + return pgtable_l4_enabled || pgtable_l5_enabled; } #define arch_vmap_pmd_supported arch_vmap_pmd_supported -- cgit v1.2.3 From 7e3811521dc3934e2ecae8458676fc4a1f62bf9f Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Tue, 25 Jul 2023 15:22:46 +0200 Subject: riscv: Implement flush_cache_vmap() The RISC-V kernel needs a sfence.vma after a page table modification: we used to rely on the vmalloc fault handling to emit an sfence.vma, but commit 7d3332be011e ("riscv: mm: Pre-allocate PGD entries for vmalloc/modules area") got rid of this path for 64-bit kernels, so now we need to explicitly emit a sfence.vma in flush_cache_vmap(). Note that we don't need to implement flush_cache_vunmap() as the generic code should emit a flush tlb after unmapping a vmalloc region. Fixes: 7d3332be011e ("riscv: mm: Pre-allocate PGD entries for vmalloc/modules area") Signed-off-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20230725132246.817726-1-alexghiti@rivosinc.com Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cacheflush.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 8091b8bf4883..b93ffddf8a61 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -37,6 +37,10 @@ static inline void flush_dcache_page(struct page *page) #define flush_icache_user_page(vma, pg, addr, len) \ flush_icache_mm(vma->vm_mm, 0) +#ifdef CONFIG_64BIT +#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) +#endif + #ifndef CONFIG_SMP #define flush_icache_all() local_flush_icache_all() -- cgit v1.2.3 From a57c27c7ad85c420b7de44c6ee56692d51709dda Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Aug 2023 15:04:59 +0200 Subject: x86/speculation: Add cpu_show_gds() prototype The newly added function has two definitions but no prototypes: drivers/base/cpu.c:605:16: error: no previous prototype for 'cpu_show_gds' [-Werror=missing-prototypes] Add a declaration next to the other ones for this file to avoid the warning. Fixes: 8974eb588283b ("x86/speculation: Add Gather Data Sampling mitigation") Signed-off-by: Arnd Bergmann Signed-off-by: Dave Hansen Tested-by: Daniel Sneddon Cc: stable@kernel.org Link: https://lore.kernel.org/all/20230809130530.1913368-1-arnd%40kernel.org --- include/linux/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 23ac87be1ff1..e006c719182b 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -72,6 +72,8 @@ extern ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf); extern ssize_t cpu_show_spec_rstack_overflow(struct device *dev, struct device_attribute *attr, char *buf); +extern ssize_t cpu_show_gds(struct device *dev, + struct device_attribute *attr, char *buf); extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, -- cgit v1.2.3 From eb3515dc99c7c85f4170b50838136b2a193f8012 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Aug 2023 15:05:00 +0200 Subject: x86: Move gds_ucode_mitigated() declaration to header The declaration got placed in the .c file of the caller, but that causes a warning for the definition: arch/x86/kernel/cpu/bugs.c:682:6: error: no previous prototype for 'gds_ucode_mitigated' [-Werror=missing-prototypes] Move it to a header where both sides can observe it instead. Fixes: 81ac7e5d74174 ("KVM: Add GDS_NO support to KVM") Signed-off-by: Arnd Bergmann Signed-off-by: Dave Hansen Tested-by: Daniel Sneddon Cc: stable@kernel.org Link: https://lore.kernel.org/all/20230809130530.1913368-2-arnd%40kernel.org --- arch/x86/include/asm/processor.h | 2 ++ arch/x86/kvm/x86.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 973db0406528..4ae2773b873d 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -731,4 +731,6 @@ bool arch_is_platform_page(u64 paddr); #define arch_is_platform_page arch_is_platform_page #endif +extern bool gds_ucode_mitigated(void); + #endif /* _ASM_X86_PROCESSOR_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 19d9ff92d699..c381770bcbf1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -314,8 +314,6 @@ u64 __read_mostly host_xcr0; static struct kmem_cache *x86_emulator_cache; -extern bool gds_ucode_mitigated(void); - /* * When called, it means the previous get/set msr reached an invalid msr. * Return true if we want to ignore/silent this failed msr access. -- cgit v1.2.3 From 438e9230d60ed8771db5770c3c795f3272ef7aae Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 18:31:47 +0200 Subject: parisc: ucmpdi2: Fix no previous prototype for '__ucmpdi2' warning Signed-off-by: Helge Deller --- arch/parisc/lib/ucmpdi2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/parisc/lib/ucmpdi2.c b/arch/parisc/lib/ucmpdi2.c index 8e6014a142ef..9d8b4dbae273 100644 --- a/arch/parisc/lib/ucmpdi2.c +++ b/arch/parisc/lib/ucmpdi2.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include union ull_union { unsigned long long ull; @@ -9,7 +10,7 @@ union ull_union { } ui; }; -int __ucmpdi2(unsigned long long a, unsigned long long b) +word_type __ucmpdi2(unsigned long long a, unsigned long long b) { union ull_union au = {.ull = a}; union ull_union bu = {.ull = b}; -- cgit v1.2.3 From 388d5bdba3fd791f734cc6687309fe59fb3343bb Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 18:32:24 +0200 Subject: parisc: parisc_ksyms: Include libgcc.h for libgcc prototypes Signed-off-by: Helge Deller --- arch/parisc/kernel/parisc_ksyms.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 00297e8e1c88..6f0c92e8149d 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -14,6 +14,7 @@ #include #include #include +#include #include EXPORT_SYMBOL(memset); @@ -92,12 +93,6 @@ EXPORT_SYMBOL($$divI_12); EXPORT_SYMBOL($$divI_14); EXPORT_SYMBOL($$divI_15); -extern void __ashrdi3(void); -extern void __ashldi3(void); -extern void __lshrdi3(void); -extern void __muldi3(void); -extern void __ucmpdi2(void); - EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__lshrdi3); -- cgit v1.2.3 From 061599c8285848fe4ec64becb278dcdd60dd3369 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 10 Aug 2023 08:55:55 +0800 Subject: ASoC: SOF: Intel: Remove duplicated include in lnl.c ./sound/soc/sof/intel/lnl.c: hda.h is included more than once. Signed-off-by: Yang Li Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230810005555.4610-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 3d919b0b6891..db94b45e53af 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -16,7 +16,6 @@ #include "hda-ipc.h" #include "../sof-audio.h" #include "mtl.h" -#include "hda.h" #include /* LunarLake ops */ -- cgit v1.2.3 From a4c59c9adc5f6b2a6b0115e3c4dc1e5127c2a01b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 19:12:16 +0200 Subject: parisc: dma: Add prototype for pcxl_dma_start Signed-off-by: Helge Deller --- arch/parisc/include/asm/dma.h | 2 ++ arch/parisc/kernel/pci-dma.c | 2 +- arch/parisc/mm/init.c | 4 ---- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/parisc/include/asm/dma.h b/arch/parisc/include/asm/dma.h index 9e8c101de902..582fb5d1a5d5 100644 --- a/arch/parisc/include/asm/dma.h +++ b/arch/parisc/include/asm/dma.h @@ -14,6 +14,8 @@ #define dma_outb outb #define dma_inb inb +extern unsigned long pcxl_dma_start; + /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up ** (or rather not merge) DMAs into manageable chunks. diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 3f6b507970eb..131d596e018f 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -39,7 +39,7 @@ static struct proc_dir_entry * proc_gsc_root __read_mostly = NULL; static unsigned long pcxl_used_bytes __read_mostly; static unsigned long pcxl_used_pages __read_mostly; -extern unsigned long pcxl_dma_start; /* Start of pcxl dma mapping area */ +unsigned long pcxl_dma_start __ro_after_init; /* pcxl dma mapping area start */ static DEFINE_SPINLOCK(pcxl_res_lock); static char *pcxl_res_map; static int pcxl_res_hint; diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 389941c7f209..a088c243edea 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -523,10 +523,6 @@ void mark_rodata_ro(void) void *parisc_vmalloc_start __ro_after_init; EXPORT_SYMBOL(parisc_vmalloc_start); -#ifdef CONFIG_PA11 -unsigned long pcxl_dma_start __ro_after_init; -#endif - void __init mem_init(void) { /* Do sanity checks on IPC (compat) structures */ -- cgit v1.2.3 From a7dfeda6fdeccab4c7c3dce9a72c4262b9530c80 Mon Sep 17 00:00:00 2001 From: Souradeep Chakrabarti Date: Wed, 9 Aug 2023 03:22:05 -0700 Subject: net: mana: Fix MANA VF unload when hardware is unresponsive When unloading the MANA driver, mana_dealloc_queues() waits for the MANA hardware to complete any inflight packets and set the pending send count to zero. But if the hardware has failed, mana_dealloc_queues() could wait forever. Fix this by adding a timeout to the wait. Set the timeout to 120 seconds, which is a somewhat arbitrary value that is more than long enough for functional hardware to complete any sends. Cc: stable@vger.kernel.org Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") Signed-off-by: Souradeep Chakrabarti Link: https://lore.kernel.org/r/1691576525-24271-1-git-send-email-schakrabarti@linux.microsoft.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microsoft/mana/mana_en.c | 37 ++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index a499e460594b..c2ad0921e893 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -2345,9 +2346,12 @@ int mana_attach(struct net_device *ndev) static int mana_dealloc_queues(struct net_device *ndev) { struct mana_port_context *apc = netdev_priv(ndev); + unsigned long timeout = jiffies + 120 * HZ; struct gdma_dev *gd = apc->ac->gdma_dev; struct mana_txq *txq; + struct sk_buff *skb; int i, err; + u32 tsleep; if (apc->port_is_up) return -EINVAL; @@ -2363,15 +2367,40 @@ static int mana_dealloc_queues(struct net_device *ndev) * to false, but it doesn't matter since mana_start_xmit() drops any * new packets due to apc->port_is_up being false. * - * Drain all the in-flight TX packets + * Drain all the in-flight TX packets. + * A timeout of 120 seconds for all the queues is used. + * This will break the while loop when h/w is not responding. + * This value of 120 has been decided here considering max + * number of queues. */ + for (i = 0; i < apc->num_queues; i++) { txq = &apc->tx_qp[i].txq; - - while (atomic_read(&txq->pending_sends) > 0) - usleep_range(1000, 2000); + tsleep = 1000; + while (atomic_read(&txq->pending_sends) > 0 && + time_before(jiffies, timeout)) { + usleep_range(tsleep, tsleep + 1000); + tsleep <<= 1; + } + if (atomic_read(&txq->pending_sends)) { + err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); + if (err) { + netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", + err, atomic_read(&txq->pending_sends), + txq->gdma_txq_id); + } + break; + } } + for (i = 0; i < apc->num_queues; i++) { + txq = &apc->tx_qp[i].txq; + while ((skb = skb_dequeue(&txq->pending_skbs))) { + mana_unmap_skb(skb, apc); + dev_kfree_skb_any(skb); + } + atomic_set(&txq->pending_sends, 0); + } /* We're 100% sure the queues can no longer be woken up, because * we're sure now mana_poll_tx_cq() can't be running. */ -- cgit v1.2.3 From db17ba719bceb52f0ae4ebca0e4c17d9a3bebf05 Mon Sep 17 00:00:00 2001 From: Nick Child Date: Wed, 9 Aug 2023 17:10:34 -0500 Subject: ibmvnic: Enforce stronger sanity checks on login response Ensure that all offsets in a login response buffer are within the size of the allocated response buffer. Any offsets or lengths that surpass the allocation are likely the result of an incomplete response buffer. In these cases, a full reset is necessary. When attempting to login, the ibmvnic device will allocate a response buffer and pass a reference to the VIOS. The VIOS will then send the ibmvnic device a LOGIN_RSP CRQ to signal that the buffer has been filled with data. If the ibmvnic device does not get a response in 20 seconds, the old buffer is freed and a new login request is sent. With 2 outstanding requests, any LOGIN_RSP CRQ's could be for the older login request. If this is the case then the login response buffer (which is for the newer login request) could be incomplete and contain invalid data. Therefore, we must enforce strict sanity checks on the response buffer values. Testing has shown that the `off_rxadd_buff_size` value is filled in last by the VIOS and will be the smoking gun for these circumstances. Until VIOS can implement a mechanism for tracking outstanding response buffers and a method for mapping a LOGIN_RSP CRQ to a particular login response buffer, the best ibmvnic can do in this situation is perform a full reset. Fixes: dff515a3e71d ("ibmvnic: Harden device login requests") Signed-off-by: Nick Child Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230809221038.51296-1-nnac123@linux.ibm.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ibm/ibmvnic.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 763d613adbcc..f4bb2c9ab9a4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -5396,6 +5396,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, int num_tx_pools; int num_rx_pools; u64 *size_array; + u32 rsp_len; int i; /* CHECK: Test/set of login_pending does not need to be atomic @@ -5447,6 +5448,23 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, ibmvnic_reset(adapter, VNIC_RESET_FATAL); return -EIO; } + + rsp_len = be32_to_cpu(login_rsp->len); + if (be32_to_cpu(login->login_rsp_len) < rsp_len || + rsp_len <= be32_to_cpu(login_rsp->off_txsubm_subcrqs) || + rsp_len <= be32_to_cpu(login_rsp->off_rxadd_subcrqs) || + rsp_len <= be32_to_cpu(login_rsp->off_rxadd_buff_size) || + rsp_len <= be32_to_cpu(login_rsp->off_supp_tx_desc)) { + /* This can happen if a login request times out and there are + * 2 outstanding login requests sent, the LOGIN_RSP crq + * could have been for the older login request. So we are + * parsing the newer response buffer which may be incomplete + */ + dev_err(dev, "FATAL: Login rsp offsets/lengths invalid\n"); + ibmvnic_reset(adapter, VNIC_RESET_FATAL); + return -EIO; + } + size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size)); /* variable buffer sizes are not supported, so just read the -- cgit v1.2.3 From 411c565b4bc63e9584a8493882bd566e35a90588 Mon Sep 17 00:00:00 2001 From: Nick Child Date: Wed, 9 Aug 2023 17:10:35 -0500 Subject: ibmvnic: Unmap DMA login rsp buffer on send login fail If the LOGIN CRQ fails to send then we must DMA unmap the response buffer. Previously, if the CRQ failed then the memory was freed without DMA unmapping. Fixes: c98d9cc4170d ("ibmvnic: send_login should check for crq errors") Signed-off-by: Nick Child Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230809221038.51296-2-nnac123@linux.ibm.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ibm/ibmvnic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index f4bb2c9ab9a4..668c67556190 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -4830,11 +4830,14 @@ static int send_login(struct ibmvnic_adapter *adapter) if (rc) { adapter->login_pending = false; netdev_err(adapter->netdev, "Failed to send login, rc=%d\n", rc); - goto buf_rsp_map_failed; + goto buf_send_failed; } return 0; +buf_send_failed: + dma_unmap_single(dev, rsp_buffer_token, rsp_buffer_size, + DMA_FROM_DEVICE); buf_rsp_map_failed: kfree(login_rsp_buffer); adapter->login_rsp_buf = NULL; -- cgit v1.2.3 From d78a671eb8996af19d6311ecdee9790d2fa479f0 Mon Sep 17 00:00:00 2001 From: Nick Child Date: Wed, 9 Aug 2023 17:10:36 -0500 Subject: ibmvnic: Handle DMA unmapping of login buffs in release functions Rather than leaving the DMA unmapping of the login buffers to the login response handler, move this work into the login release functions. Previously, these functions were only used for freeing the allocated buffers. This could lead to issues if there are more than one outstanding login buffer requests, which is possible if a login request times out. If a login request times out, then there is another call to send login. The send login function makes a call to the login buffer release function. In the past, this freed the buffers but did not DMA unmap. Therefore, the VIOS could still write to the old login (now freed) buffer. It is for this reason that it is a good idea to leave the DMA unmap call to the login buffers release function. Since the login buffer release functions now handle DMA unmapping, remove the duplicate DMA unmapping in handle_login_rsp(). Fixes: dff515a3e71d ("ibmvnic: Harden device login requests") Signed-off-by: Nick Child Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230809221038.51296-3-nnac123@linux.ibm.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ibm/ibmvnic.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 668c67556190..77b0a744fa88 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1588,12 +1588,22 @@ static int ibmvnic_login(struct net_device *netdev) static void release_login_buffer(struct ibmvnic_adapter *adapter) { + if (!adapter->login_buf) + return; + + dma_unmap_single(&adapter->vdev->dev, adapter->login_buf_token, + adapter->login_buf_sz, DMA_TO_DEVICE); kfree(adapter->login_buf); adapter->login_buf = NULL; } static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter) { + if (!adapter->login_rsp_buf) + return; + + dma_unmap_single(&adapter->vdev->dev, adapter->login_rsp_buf_token, + adapter->login_rsp_buf_sz, DMA_FROM_DEVICE); kfree(adapter->login_rsp_buf); adapter->login_rsp_buf = NULL; } @@ -5411,11 +5421,6 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, } adapter->login_pending = false; - dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz, - DMA_TO_DEVICE); - dma_unmap_single(dev, adapter->login_rsp_buf_token, - adapter->login_rsp_buf_sz, DMA_FROM_DEVICE); - /* If the number of queues requested can't be allocated by the * server, the login response will return with code 1. We will need * to resend the login buffer with fewer queues requested. -- cgit v1.2.3 From 23cc5f667453ca7645a24c8d21bf84dbf61107b2 Mon Sep 17 00:00:00 2001 From: Nick Child Date: Wed, 9 Aug 2023 17:10:37 -0500 Subject: ibmvnic: Do partial reset on login failure Perform a partial reset before sending a login request if any of the following are true: 1. If a previous request times out. This can be dangerous because the VIOS could still receive the old login request at any point after the timeout. Therefore, it is best to re-register the CRQ's and sub-CRQ's before retrying. 2. If the previous request returns an error that is not described in PAPR. PAPR provides procedures if the login returns with partial success or aborted return codes (section L.5.1) but other values do not have a defined procedure. Previously, these conditions just returned error from the login function rather than trying to resolve the issue. This can cause further issues since most callers of the login function are not prepared to handle an error when logging in. This improper cleanup can lead to the device being permanently DOWN'd. For example, if the VIOS believes that the device is already logged in then it will return INVALID_STATE (-7). If we never re-register CRQ's then it will always think that the device is already logged in. This leaves the device inoperable. The partial reset involves freeing the sub-CRQs, freeing the CRQ then registering and initializing a new CRQ and sub-CRQs. This essentially restarts all communication with VIOS to allow for a fresh login attempt that will be unhindered by any previous failed attempts. Fixes: dff515a3e71d ("ibmvnic: Harden device login requests") Signed-off-by: Nick Child Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230809221038.51296-4-nnac123@linux.ibm.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ibm/ibmvnic.c | 46 +++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 77b0a744fa88..e9619957d58a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -97,6 +97,8 @@ static int pending_scrq(struct ibmvnic_adapter *, static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *, struct ibmvnic_sub_crq_queue *); static int ibmvnic_poll(struct napi_struct *napi, int data); +static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter); +static inline void reinit_init_done(struct ibmvnic_adapter *adapter); static void send_query_map(struct ibmvnic_adapter *adapter); static int send_request_map(struct ibmvnic_adapter *, dma_addr_t, u32, u8); static int send_request_unmap(struct ibmvnic_adapter *, u8); @@ -1527,11 +1529,9 @@ static int ibmvnic_login(struct net_device *netdev) if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { - netdev_warn(netdev, "Login timed out, retrying...\n"); - retry = true; - adapter->init_done_rc = 0; - retry_count++; - continue; + netdev_warn(netdev, "Login timed out\n"); + adapter->login_pending = false; + goto partial_reset; } if (adapter->init_done_rc == ABORTED) { @@ -1576,7 +1576,41 @@ static int ibmvnic_login(struct net_device *netdev) } else if (adapter->init_done_rc) { netdev_warn(netdev, "Adapter login failed, init_done_rc = %d\n", adapter->init_done_rc); - return -EIO; + +partial_reset: + /* adapter login failed, so free any CRQs or sub-CRQs + * and register again before attempting to login again. + * If we don't do this then the VIOS may think that + * we are already logged in and reject any subsequent + * attempts + */ + netdev_warn(netdev, + "Freeing and re-registering CRQs before attempting to login again\n"); + retry = true; + adapter->init_done_rc = 0; + retry_count++; + release_sub_crqs(adapter, true); + reinit_init_done(adapter); + release_crq_queue(adapter); + /* If we don't sleep here then we risk an unnecessary + * failover event from the VIOS. This is a known VIOS + * issue caused by a vnic device freeing and registering + * a CRQ too quickly. + */ + msleep(1500); + rc = init_crq_queue(adapter); + if (rc) { + netdev_err(netdev, "login recovery: init CRQ failed %d\n", + rc); + return -EIO; + } + + rc = ibmvnic_reset_init(adapter, false); + if (rc) { + netdev_err(netdev, "login recovery: Reset init failed %d\n", + rc); + return -EIO; + } } } while (retry); -- cgit v1.2.3 From 6db541ae279bd4e76dbd939e5fbf298396166242 Mon Sep 17 00:00:00 2001 From: Nick Child Date: Wed, 9 Aug 2023 17:10:38 -0500 Subject: ibmvnic: Ensure login failure recovery is safe from other resets If a login request fails, the recovery process should be protected against parallel resets. It is a known issue that freeing and registering CRQ's in quick succession can result in a failover CRQ from the VIOS. Processing a failover during login recovery is dangerous for two reasons: 1. This will result in two parallel initialization processes, this can cause serious issues during login. 2. It is possible that the failover CRQ is received but never executed. We get notified of a pending failover through a transport event CRQ. The reset is not performed until a INIT CRQ request is received. Previously, if CRQ init fails during login recovery, then the ibmvnic irq is freed and the login process returned error. If failover_pending is true (a transport event was received), then the ibmvnic device would never be able to process the reset since it cannot receive the CRQ_INIT request due to the irq being freed. This leaved the device in a inoperable state. Therefore, the login failure recovery process must be hardened against these possible issues. Possible failovers (due to quick CRQ free and init) must be avoided and any issues during re-initialization should be dealt with instead of being propagated up the stack. This logic is similar to that of ibmvnic_probe(). Fixes: dff515a3e71d ("ibmvnic: Harden device login requests") Signed-off-by: Nick Child Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230809221038.51296-5-nnac123@linux.ibm.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ibm/ibmvnic.c | 68 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index e9619957d58a..df76cdaddcfb 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -116,6 +116,7 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter, static void free_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb); static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter); +static void flush_reset_queue(struct ibmvnic_adapter *adapter); struct ibmvnic_stat { char name[ETH_GSTRING_LEN]; @@ -1507,8 +1508,8 @@ static const char *adapter_state_to_string(enum vnic_state state) static int ibmvnic_login(struct net_device *netdev) { + unsigned long flags, timeout = msecs_to_jiffies(20000); struct ibmvnic_adapter *adapter = netdev_priv(netdev); - unsigned long timeout = msecs_to_jiffies(20000); int retry_count = 0; int retries = 10; bool retry; @@ -1573,6 +1574,7 @@ static int ibmvnic_login(struct net_device *netdev) "SCRQ irq initialization failed\n"); return rc; } + /* Default/timeout error handling, reset and start fresh */ } else if (adapter->init_done_rc) { netdev_warn(netdev, "Adapter login failed, init_done_rc = %d\n", adapter->init_done_rc); @@ -1588,29 +1590,53 @@ partial_reset: "Freeing and re-registering CRQs before attempting to login again\n"); retry = true; adapter->init_done_rc = 0; - retry_count++; release_sub_crqs(adapter, true); - reinit_init_done(adapter); - release_crq_queue(adapter); - /* If we don't sleep here then we risk an unnecessary - * failover event from the VIOS. This is a known VIOS - * issue caused by a vnic device freeing and registering - * a CRQ too quickly. + /* Much of this is similar logic as ibmvnic_probe(), + * we are essentially re-initializing communication + * with the server. We really should not run any + * resets/failovers here because this is already a form + * of reset and we do not want parallel resets occurring */ - msleep(1500); - rc = init_crq_queue(adapter); - if (rc) { - netdev_err(netdev, "login recovery: init CRQ failed %d\n", - rc); - return -EIO; - } + do { + reinit_init_done(adapter); + /* Clear any failovers we got in the previous + * pass since we are re-initializing the CRQ + */ + adapter->failover_pending = false; + release_crq_queue(adapter); + /* If we don't sleep here then we risk an + * unnecessary failover event from the VIOS. + * This is a known VIOS issue caused by a vnic + * device freeing and registering a CRQ too + * quickly. + */ + msleep(1500); + /* Avoid any resets, since we are currently + * resetting. + */ + spin_lock_irqsave(&adapter->rwi_lock, flags); + flush_reset_queue(adapter); + spin_unlock_irqrestore(&adapter->rwi_lock, + flags); + + rc = init_crq_queue(adapter); + if (rc) { + netdev_err(netdev, "login recovery: init CRQ failed %d\n", + rc); + return -EIO; + } - rc = ibmvnic_reset_init(adapter, false); - if (rc) { - netdev_err(netdev, "login recovery: Reset init failed %d\n", - rc); - return -EIO; - } + rc = ibmvnic_reset_init(adapter, false); + if (rc) + netdev_err(netdev, "login recovery: Reset init failed %d\n", + rc); + /* IBMVNIC_CRQ_INIT will return EAGAIN if it + * fails, since ibmvnic_reset_init will free + * irq's in failure, we won't be able to receive + * new CRQs so we need to keep trying. probe() + * handles this similarly. + */ + } while (rc == -EAGAIN && retry_count++ < retries); } } while (retry); -- cgit v1.2.3 From 6b486676b41c369fe822fe65771ffda7eeb3ea6f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 8 Aug 2023 11:09:17 -0700 Subject: net: tls: set MSG_SPLICE_PAGES consistently We used to change the flags for the last segment, because non-last segments had the MSG_SENDPAGE_NOTLAST flag set. That flag is no longer a thing so remove the setting. Since flags most likely don't have MSG_SPLICE_PAGES set this avoids passing parts of the sg as splice and parts as non-splice. Before commit under Fixes we'd have called tcp_sendpage() which would add the MSG_SPLICE_PAGES. Why this leads to trouble remains unclear but Tariq reports hitting the WARN_ON(!sendpage_ok()) due to page refcount of 0. Fixes: e117dcfd646e ("tls: Inline do_tcp_sendpages()") Reported-by: Tariq Toukan Link: https://lore.kernel.org/all/4c49176f-147a-4283-f1b1-32aac7b4b996@gmail.com/ Tested-by: Tariq Toukan Link: https://lore.kernel.org/r/20230808180917.1243540-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/tls/tls_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index b6896126bb92..4a8ee2f6badb 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -139,9 +139,6 @@ int tls_push_sg(struct sock *sk, ctx->splicing_pages = true; while (1) { - if (sg_is_last(sg)) - msg.msg_flags = flags; - /* is sending application-limited? */ tcp_rate_check_app_limited(sk); p = sg_page(sg); -- cgit v1.2.3 From 5e3d20617b055e725e785e0058426368269949f3 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 9 Aug 2023 10:09:02 +0800 Subject: net: hns3: fix strscpy causing content truncation issue hns3_dbg_fill_content()/hclge_dbg_fill_content() is aim to integrate some items to a string for content, and we add '\n' and '\0' in the last two bytes of content. strscpy() will add '\0' in the last byte of destination buffer(one of items), it result in finishing content print ahead of schedule and some dump content truncation. One Error log shows as below: cat mac_list/uc UC MAC_LIST: Expected: UC MAC_LIST: FUNC_ID MAC_ADDR STATE pf 00:2b:19:05:03:00 ACTIVE The destination buffer is length-bounded and not required to be NUL-terminated, so just change strscpy() to memcpy() to fix it. Fixes: 1cf3d5567f27 ("net: hns3: fix strncpy() not using dest-buf length as length issue") Signed-off-by: Hao Chen Signed-off-by: Jijie Shao Link: https://lore.kernel.org/r/20230809020902.1941471-1-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 52546f625c8b..f276b5ecb431 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -464,9 +464,9 @@ static void hns3_dbg_fill_content(char *content, u16 len, if (result) { if (item_len < strlen(result[i])) break; - strscpy(pos, result[i], strlen(result[i])); + memcpy(pos, result[i], strlen(result[i])); } else { - strscpy(pos, items[i].name, strlen(items[i].name)); + memcpy(pos, items[i].name, strlen(items[i].name)); } pos += item_len; len -= item_len; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 409db2e70965..0fb2eaee3e8a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -111,9 +111,9 @@ static void hclge_dbg_fill_content(char *content, u16 len, if (result) { if (item_len < strlen(result[i])) break; - strscpy(pos, result[i], strlen(result[i])); + memcpy(pos, result[i], strlen(result[i])); } else { - strscpy(pos, items[i].name, strlen(items[i].name)); + memcpy(pos, items[i].name, strlen(items[i].name)); } pos += item_len; len -= item_len; -- cgit v1.2.3 From 5363fc488da579923edf6a2fdca3d3b651dd800b Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Wed, 9 Aug 2023 21:44:35 -0700 Subject: RDMA/bnxt_re: Properly order ib_device_unalloc() to avoid UAF ib_dealloc_device() should be called only after device cleanup. Fix the dealloc sequence. Fixes: 6d758147c7b8 ("RDMA/bnxt_re: Use auxiliary driver interface") Link: https://lore.kernel.org/r/1691642677-21369-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index b42166fe7454..1c7646057893 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1526,8 +1526,8 @@ static void bnxt_re_remove(struct auxiliary_device *adev) } bnxt_re_setup_cc(rdev, false); ib_unregister_device(&rdev->ibdev); - ib_dealloc_device(&rdev->ibdev); bnxt_re_dev_uninit(rdev); + ib_dealloc_device(&rdev->ibdev); skip_remove: mutex_unlock(&bnxt_re_mutex); } -- cgit v1.2.3 From 5ac8480ae4d01f0ca5dfd561884424046df2478a Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Wed, 9 Aug 2023 21:44:36 -0700 Subject: RDMA/bnxt_re: Fix error handling in probe failure path During bnxt_re_dev_init(), when bnxt_re_setup_chip_ctx() fails unregister with L2 first before bailing out probe. Fixes: ae8637e13185 ("RDMA/bnxt_re: Add chip context to identify 57500 series") Link: https://lore.kernel.org/r/1691642677-21369-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 1c7646057893..63e98e2d3596 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1253,6 +1253,8 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) rc = bnxt_re_setup_chip_ctx(rdev, wqe_mode); if (rc) { + bnxt_unregister_dev(rdev->en_dev); + clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); ibdev_err(&rdev->ibdev, "Failed to get chip context\n"); return -EINVAL; } -- cgit v1.2.3 From 64b632654b97319b253c2c902fe4c11349aaa70f Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Wed, 9 Aug 2023 21:44:37 -0700 Subject: RDMA/bnxt_re: Initialize dpi_tbl_lock mutex Fix the missing dpi_tbl_lock mutex initialization. Fixes: 0ac20faf5d83 ("RDMA/bnxt_re: Reorg the bar mapping") Link: https://lore.kernel.org/r/1691642677-21369-4-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Kashyap Desai Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 5fd8f7c90bb0..739d942761d1 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -819,6 +819,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res, } memset((u8 *)dpit->tbl, 0xFF, bytes); + mutex_init(&res->dpi_tbl_lock); dpit->priv_db = dpit->ucreg.bar_reg + dpit->ucreg.offset; return 0; -- cgit v1.2.3 From 547259580dfa9a5d345dd1b46fd5e9977654c1cc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 19:56:19 +0200 Subject: parisc: Move proc_mckinley_root and proc_runway_root to sba_iommu Clean up the procfs root entries for gsc, runway, and mckinley busses. Signed-off-by: Helge Deller --- arch/parisc/kernel/pci-dma.c | 2 +- arch/parisc/kernel/setup.c | 48 -------------------------------------------- drivers/parisc/sba_iommu.c | 6 ++++++ 3 files changed, 7 insertions(+), 49 deletions(-) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 131d596e018f..bf9f192c826e 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -381,7 +381,7 @@ pcxl_dma_init(void) pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL, get_order(pcxl_res_size)); memset(pcxl_res_map, 0, pcxl_res_size); - proc_gsc_root = proc_mkdir("gsc", NULL); + proc_gsc_root = proc_mkdir("bus/gsc", NULL); if (!proc_gsc_root) printk(KERN_WARNING "pcxl_dma_init: Unable to create gsc /proc dir entry\n"); diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 573f8303e2b0..211a4afdd282 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -40,11 +40,6 @@ static char __initdata command_line[COMMAND_LINE_SIZE]; -/* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */ -struct proc_dir_entry * proc_runway_root __read_mostly = NULL; -struct proc_dir_entry * proc_gsc_root __read_mostly = NULL; -struct proc_dir_entry * proc_mckinley_root __read_mostly = NULL; - static void __init setup_cmdline(char **cmdline_p) { extern unsigned int boot_args[]; @@ -196,48 +191,6 @@ const struct seq_operations cpuinfo_op = { .show = show_cpuinfo }; -static void __init parisc_proc_mkdir(void) -{ - /* - ** Can't call proc_mkdir() until after proc_root_init() has been - ** called by start_kernel(). In other words, this code can't - ** live in arch/.../setup.c because start_parisc() calls - ** start_kernel(). - */ - switch (boot_cpu_data.cpu_type) { - case pcxl: - case pcxl2: - if (NULL == proc_gsc_root) - { - proc_gsc_root = proc_mkdir("bus/gsc", NULL); - } - break; - case pcxt_: - case pcxu: - case pcxu_: - case pcxw: - case pcxw_: - case pcxw2: - if (NULL == proc_runway_root) - { - proc_runway_root = proc_mkdir("bus/runway", NULL); - } - break; - case mako: - case mako2: - if (NULL == proc_mckinley_root) - { - proc_mckinley_root = proc_mkdir("bus/mckinley", NULL); - } - break; - default: - /* FIXME: this was added to prevent the compiler - * complaining about missing pcx, pcxs and pcxt - * I'm assuming they have neither gsc nor runway */ - break; - } -} - static struct resource central_bus = { .name = "Central Bus", .start = F_EXTEND(0xfff80000), @@ -294,7 +247,6 @@ static int __init parisc_init(void) { u32 osid = (OS_ID_LINUX << 16); - parisc_proc_mkdir(); parisc_init_resources(); do_device_inventory(); /* probe for hardware */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index bf3405f4289e..8b1dcd537020 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -121,6 +121,8 @@ module_param(sba_reserve_agpgart, int, 0444); MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART"); #endif +struct proc_dir_entry *proc_runway_root __ro_after_init; +struct proc_dir_entry *proc_mckinley_root __ro_after_init; /************************************ ** SBA register read and write support @@ -1968,11 +1970,15 @@ static int __init sba_driver_callback(struct parisc_device *dev) #ifdef CONFIG_PROC_FS switch (dev->id.hversion) { case PLUTO_MCKINLEY_PORT: + if (!proc_mckinley_root) + proc_mckinley_root = proc_mkdir("bus/mckinley", NULL); root = proc_mckinley_root; break; case ASTRO_RUNWAY_PORT: case IKE_MERCED_PORT: default: + if (!proc_runway_root) + proc_runway_root = proc_mkdir("bus/runway", NULL); root = proc_runway_root; break; } -- cgit v1.2.3 From 66f80386a99f2773611e1b537ad045061fdd92ec Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 20:23:01 +0200 Subject: parisc: unaligned: Include linux/sysctl.h for unaligned_enabled Fix sparse warning that unaligned_enabled wasn't declared. Signed-off-by: Helge Deller --- arch/parisc/kernel/unaligned.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 813062701922..170d0dda4213 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 2c9227fd1c7e508f55eb4a38e8205f317e7c4ac9 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 22:32:24 +0200 Subject: parisc: processor: Include asm/smp.h for init_per_cpu() Fix sparse warning that init_per_cpu() isn't declared. Signed-off-by: Helge Deller --- arch/parisc/kernel/processor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 00b0df97afb1..762289b9984e 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include /* for struct irq_region */ #include -- cgit v1.2.3 From b967f48d0240fa9b3ac0bfd7135647985016826e Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 22:42:57 +0200 Subject: parisc: boot: Nuke some sparse warnings in decompressor Signed-off-by: Helge Deller --- arch/parisc/boot/compressed/misc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c index 7ee49f5881d1..d389359e22ac 100644 --- a/arch/parisc/boot/compressed/misc.c +++ b/arch/parisc/boot/compressed/misc.c @@ -117,7 +117,7 @@ char *strchr(const char *s, int c) return NULL; } -int puts(const char *s) +static int puts(const char *s) { const char *nuline = s; @@ -172,7 +172,7 @@ static int print_num(unsigned long num, int base) return 0; } -int printf(const char *fmt, ...) +static int printf(const char *fmt, ...) { va_list args; int i = 0; @@ -204,13 +204,13 @@ void abort(void) } #undef malloc -void *malloc(size_t size) +static void *malloc(size_t size) { return malloc_gzip(size); } #undef free -void free(void *ptr) +static void free(void *ptr) { return free_gzip(ptr); } @@ -278,7 +278,7 @@ static void parse_elf(void *output) free(phdrs); } -unsigned long decompress_kernel(unsigned int started_wide, +asmlinkage unsigned long __visible decompress_kernel(unsigned int started_wide, unsigned int command_line, const unsigned int rd_start, const unsigned int rd_end) -- cgit v1.2.3 From 2794f8ecb483b680610968423179005758a5ce63 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 22:51:54 +0200 Subject: parisc: ftrace: Add declaration for ftrace_function_trampoline() Make sparse happy by adding declaration for ftrace_function_trampoline(). Signed-off-by: Helge Deller --- arch/parisc/include/asm/ftrace.h | 4 ++++ arch/parisc/kernel/ftrace.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/parisc/include/asm/ftrace.h b/arch/parisc/include/asm/ftrace.h index a7cf0d05ccf4..f1cc1ee3a647 100644 --- a/arch/parisc/include/asm/ftrace.h +++ b/arch/parisc/include/asm/ftrace.h @@ -12,6 +12,10 @@ extern void mcount(void); extern unsigned long sys_call_table[]; extern unsigned long return_address(unsigned int); +struct ftrace_regs; +extern void ftrace_function_trampoline(unsigned long parent, + unsigned long self_addr, unsigned long org_sp_gr3, + struct ftrace_regs *fregs); #ifdef CONFIG_DYNAMIC_FTRACE extern void ftrace_caller(void); diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c index 4d392e4ed358..d1defb9ede70 100644 --- a/arch/parisc/kernel/ftrace.c +++ b/arch/parisc/kernel/ftrace.c @@ -53,7 +53,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent, static ftrace_func_t ftrace_func; -void notrace __hot ftrace_function_trampoline(unsigned long parent, +asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent, unsigned long self_addr, unsigned long org_sp_gr3, struct ftrace_regs *fregs) -- cgit v1.2.3 From d863066e6ce0a70c479a7f618088912ac0ba44ac Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Aug 2023 23:00:18 +0200 Subject: parisc: perf: Make cpu_device variable static Signed-off-by: Helge Deller --- arch/parisc/kernel/perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index 90b04d8af212..b0f0816879df 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -57,7 +57,7 @@ struct rdr_tbl_ent { static int perf_processor_interface __read_mostly = UNKNOWN_INTF; static int perf_enabled __read_mostly; static DEFINE_SPINLOCK(perf_lock); -struct parisc_device *cpu_device __read_mostly; +static struct parisc_device *cpu_device __read_mostly; /* RDRs to write for PCX-W */ static const int perf_rdrs_W[] = -- cgit v1.2.3 From a7a7dabb5dd72d2875bc3ce56f94ea5ceb259d5b Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 9 Aug 2023 10:04:40 +0800 Subject: nvme: core: don't hold rcu read lock in nvme_ns_chr_uring_cmd_iopoll Now nvme_ns_chr_uring_cmd_iopoll() has switched to request based io polling, and the associated NS is guaranteed to be live in case of io polling, so request is guaranteed to be valid because blk-mq uses pre-allocated request pool. Remove the rcu read lock in nvme_ns_chr_uring_cmd_iopoll(), which isn't needed any more after switching to request based io polling. Fix "BUG: sleeping function called from invalid context" because set_page_dirty_lock() from blk_rq_unmap_user() may sleep. Fixes: 585079b6e425 ("nvme: wire up async polling for io passthrough commands") Reported-by: Guangwu Zhang Cc: Kanchan Joshi Cc: Anuj Gupta Signed-off-by: Ming Lei Tested-by: Guangwu Zhang Link: https://lore.kernel.org/r/20230809020440.174682-1-ming.lei@redhat.com Signed-off-by: Jens Axboe --- drivers/nvme/host/ioctl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index 5c3250f36ce7..d39f3219358b 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -786,11 +786,9 @@ int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd, if (!(ioucmd->flags & IORING_URING_CMD_POLLED)) return 0; - rcu_read_lock(); req = READ_ONCE(ioucmd->cookie); if (req && blk_rq_is_poll(req)) ret = blk_rq_poll(req, iob, poll_flags); - rcu_read_unlock(); return ret; } #ifdef CONFIG_NVME_MULTIPATH -- cgit v1.2.3 From 3477144c878a52fc3938a529186e81ea030e7779 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Fri, 11 Aug 2023 11:32:09 +0200 Subject: driver core: cpu: Fix the fallback cpu_show_gds() name In 6524c798b727 ("driver core: cpu: Make cpu_show_not_affected() static") I fat-fingered the name of cpu_show_gds(). Usually, I'd rebase but since those are extraordinary embargoed times, the commit above was already pulled into another tree so no no. Therefore, fix it ontop. Fixes: 6524c798b727 ("driver core: cpu: Make cpu_show_not_affected() static") Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230811095831.27513-1-bp@alien8.de --- drivers/base/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index d7300d885822..fe6690ecf563 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -532,7 +532,7 @@ CPU_SHOW_VULN_FALLBACK(srbds); CPU_SHOW_VULN_FALLBACK(mmio_stale_data); CPU_SHOW_VULN_FALLBACK(retbleed); CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); -CPU_SHOW_VULN_FALLBACK(gather_data_sampling); +CPU_SHOW_VULN_FALLBACK(gds); static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); @@ -546,7 +546,7 @@ static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL); static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL); static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); -static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gather_data_sampling, NULL); +static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, -- cgit v1.2.3 From 33f83d13ded164cd49ce2a3bd2770115abc64e6f Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 10 Aug 2023 18:00:44 -0400 Subject: gpio: ws16c48: Fix off-by-one error in WS16C48 resource region extent The WinSystems WS16C48 I/O address region spans offsets 0x0 through 0xA, which is a total of 11 bytes. Fix the WS16C48_EXTENT define to the correct value of 11 so that access to necessary device registers is properly requested in the ws16c48_probe() callback by the devm_request_region() function call. Fixes: 2c05a0f29f41 ("gpio: ws16c48: Implement and utilize register structures") Cc: stable@vger.kernel.org Cc: Paul Demetrotion Signed-off-by: William Breathitt Gray Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ws16c48.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index e73885a4dc32..afb42a8e916f 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -18,7 +18,7 @@ #include #include -#define WS16C48_EXTENT 10 +#define WS16C48_EXTENT 11 #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) static unsigned int base[MAX_NUM_WS16C48]; -- cgit v1.2.3 From 6dbef74aeb090d6bee7d64ef3fa82ae6fa53f271 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 11 Aug 2023 23:37:05 +0300 Subject: x86/cpu/amd: Enable Zenbleed fix for AMD Custom APU 0405 Commit 522b1d69219d ("x86/cpu/amd: Add a Zenbleed fix") provided a fix for the Zen2 VZEROUPPER data corruption bug affecting a range of CPU models, but the AMD Custom APU 0405 found on SteamDeck was not listed, although it is clearly affected by the vulnerability. Add this CPU variant to the Zenbleed erratum list, in order to unconditionally enable the fallback fix until a proper microcode update is available. Fixes: 522b1d69219d ("x86/cpu/amd: Add a Zenbleed fix") Signed-off-by: Cristian Ciocaltea Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230811203705.1699914-1-cristian.ciocaltea@collabora.com --- arch/x86/kernel/cpu/amd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 26ad7ca423e7..c15b4f02b4cf 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -73,6 +73,7 @@ static const int amd_erratum_1054[] = static const int amd_zenbleed[] = AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf), AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), + AMD_MODEL_RANGE(0x17, 0x90, 0x0, 0x91, 0xf), AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) -- cgit v1.2.3 From 51e5e551af53259e0274b0cd4ff83d8351fb8c40 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 8 Aug 2023 12:48:36 +0300 Subject: tpm: tpm_tis: Fix UPX-i11 DMI_MATCH condition The patch which made it to the kernel somehow changed the match condition from DMI_MATCH(DMI_PRODUCT_NAME, "UPX-TGL01") to DMI_MATCH(DMI_PRODUCT_VERSION, "UPX-TGL") Revert back to the correct match condition to disable the interrupt mode on the board. Cc: stable@vger.kernel.org # v6.4+ Fixes: edb13d7bb034 ("tpm: tpm_tis: Disable interrupts *only* for AEON UPX-i11") Link: https://lore.kernel.org/lkml/20230524085844.11580-1-peter.ujfalusi@linux.intel.com/ Signed-off-by: Peter Ujfalusi Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ac4daaf294a3..3c0f68b9e44f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -183,7 +183,7 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = { .ident = "UPX-TGL", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), - DMI_MATCH(DMI_PRODUCT_VERSION, "UPX-TGL"), + DMI_MATCH(DMI_PRODUCT_NAME, "UPX-TGL01"), }, }, {} -- cgit v1.2.3 From 6aaf663ee04a80b445f8f5abff53cb92cb583c88 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sat, 12 Aug 2023 02:07:10 +0300 Subject: tpm_tis: Opt-in interrupts Cc: stable@vger.kernel.org # v6.4+ Link: https://lore.kernel.org/linux-integrity/CAHk-=whRVp4h8uWOX1YO+Y99+44u4s=XxMK4v00B6F1mOfqPLg@mail.gmail.com/ Fixes: e644b2f498d2 ("tpm, tpm_tis: Enable interrupt test") Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 3c0f68b9e44f..7fa3d91042b2 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -89,7 +89,7 @@ static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) tpm_tis_flush(iobase); } -static int interrupts = -1; +static int interrupts; module_param(interrupts, int, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); -- cgit v1.2.3 From c8afaa1b0f8bc93d013ab2ea6b9649958af3f1d3 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 12 Aug 2023 18:15:54 +0200 Subject: locking: remove spin_lock_prefetch The only remaining consumer is new_inode, where it showed up in 2001 as commit c37fa164f793 ("v2.4.9.9 -> v2.4.9.10") in a historical repo [1] with a changelog which does not mention it. Since then the line got only touched up to keep compiling. While it may have been of benefit back in the day, it is guaranteed to at best not get in the way in the multicore setting -- as the code performs *a lot* of work between the prefetch and actual lock acquire, any contention means the cacheline is already invalid by the time the routine calls spin_lock(). It adds spurious traffic, for short. On top of it prefetch is notoriously tricky to use for single-threaded purposes, making it questionable from the get go. As such, remove it. I admit upfront I did not see value in benchmarking this change, but I can do it if that is deemed appropriate. Removal from new_inode and of the entire thing are in the same patch as requested by Linus, so whatever weird looks can be directed at that guy. Link: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/fs/inode.c?id=c37fa164f793735b32aa3f53154ff1a7659e6442 [1] Signed-off-by: Mateusz Guzik Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/processor.h | 13 ------------- arch/arm64/include/asm/processor.h | 8 -------- arch/ia64/include/asm/processor.h | 3 --- .../include/asm/mach-cavium-octeon/cpu-feature-overrides.h | 2 -- arch/powerpc/include/asm/processor.h | 3 --- arch/sparc/include/asm/processor_64.h | 3 --- arch/x86/include/asm/processor.h | 6 ------ fs/inode.c | 3 --- include/linux/prefetch.h | 7 +------ 9 files changed, 1 insertion(+), 47 deletions(-) diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index 714abe494e5f..55bb1c09fd39 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h @@ -47,12 +47,6 @@ unsigned long __get_wchan(struct task_struct *p); #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH - -#ifndef CONFIG_SMP -/* Nothing to prefetch. */ -#define spin_lock_prefetch(lock) do { } while (0) -#endif extern inline void prefetch(const void *ptr) { @@ -64,11 +58,4 @@ extern inline void prefetchw(const void *ptr) __builtin_prefetch(ptr, 1, 3); } -#ifdef CONFIG_SMP -extern inline void spin_lock_prefetch(const void *ptr) -{ - __builtin_prefetch(ptr, 1, 3); -} -#endif - #endif /* __ASM_ALPHA_PROCESSOR_H */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 3918f2a67970..e5bc54522e71 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -359,14 +359,6 @@ static inline void prefetchw(const void *ptr) asm volatile("prfm pstl1keep, %a0\n" : : "p" (ptr)); } -#define ARCH_HAS_SPINLOCK_PREFETCH -static inline void spin_lock_prefetch(const void *ptr) -{ - asm volatile(ARM64_LSE_ATOMIC_INSN( - "prfm pstl1strm, %a0", - "nop") : : "p" (ptr)); -} - extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */ extern void __init minsigstksz_setup(void); diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index d1978e004054..47e3801b526a 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -634,7 +634,6 @@ ia64_imva (void *addr) #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH #define PREFETCH_STRIDE L1_CACHE_BYTES static inline void @@ -649,8 +648,6 @@ prefetchw (const void *x) ia64_lfetch_excl(ia64_lfhint_none, x); } -#define spin_lock_prefetch(x) prefetchw(x) - extern unsigned long boot_option_idle_override; enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT, diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h index 9151dcd9d0d5..af9cea21c853 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h @@ -58,8 +58,6 @@ #define cpu_has_rixi (cpu_data[0].cputype != CPU_CAVIUM_OCTEON) -#define ARCH_HAS_SPINLOCK_PREFETCH 1 -#define spin_lock_prefetch(x) prefetch(x) #define PREFETCH_STRIDE 128 #ifdef __OCTEON__ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 8a6754ffdc7e..a6c7069bec5d 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -393,7 +393,6 @@ int validate_sp_size(unsigned long sp, struct task_struct *p, */ #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH static inline void prefetch(const void *x) { @@ -411,8 +410,6 @@ static inline void prefetchw(const void *x) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x)); } -#define spin_lock_prefetch(x) prefetchw(x) - /* asm stubs */ extern unsigned long isa300_idle_stop_noloss(unsigned long psscr_val); extern unsigned long isa300_idle_stop_mayloss(unsigned long psscr_val); diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 2667f35d5ea5..0a0d5c3d184c 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -213,7 +213,6 @@ unsigned long __get_wchan(struct task_struct *task); */ #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH static inline void prefetch(const void *x) { @@ -239,8 +238,6 @@ static inline void prefetchw(const void *x) : "r" (x)); } -#define spin_lock_prefetch(x) prefetchw(x) - #define HAVE_ARCH_PICK_MMAP_LAYOUT int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4ae2773b873d..fd750247ca89 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -586,7 +586,6 @@ extern char ignore_fpu_irq; #define HAVE_ARCH_PICK_MMAP_LAYOUT 1 #define ARCH_HAS_PREFETCHW -#define ARCH_HAS_SPINLOCK_PREFETCH #ifdef CONFIG_X86_32 # define BASE_PREFETCH "" @@ -620,11 +619,6 @@ static __always_inline void prefetchw(const void *x) "m" (*(const char *)x)); } -static inline void spin_lock_prefetch(const void *x) -{ - prefetchw(x); -} - #define TOP_OF_INIT_STACK ((unsigned long)&init_stack + sizeof(init_stack) - \ TOP_OF_KERNEL_STACK_PADDING) diff --git a/fs/inode.c b/fs/inode.c index 8fefb69e1f84..67611a360031 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -16,7 +16,6 @@ #include #include #include -#include #include /* for inode_has_buffers */ #include #include @@ -1041,8 +1040,6 @@ struct inode *new_inode(struct super_block *sb) { struct inode *inode; - spin_lock_prefetch(&sb->s_inode_list_lock); - inode = new_inode_pseudo(sb); if (inode) inode_sb_list_add(inode); diff --git a/include/linux/prefetch.h b/include/linux/prefetch.h index b83a3f944f28..b068e2e60939 100644 --- a/include/linux/prefetch.h +++ b/include/linux/prefetch.h @@ -25,11 +25,10 @@ struct page; prefetch() should be defined by the architecture, if not, the #define below provides a no-op define. - There are 3 prefetch() macros: + There are 2 prefetch() macros: prefetch(x) - prefetches the cacheline at "x" for read prefetchw(x) - prefetches the cacheline at "x" for write - spin_lock_prefetch(x) - prefetches the spinlock *x for taking there is also PREFETCH_STRIDE which is the architecure-preferred "lookahead" size for prefetching streamed operations. @@ -44,10 +43,6 @@ struct page; #define prefetchw(x) __builtin_prefetch(x,1) #endif -#ifndef ARCH_HAS_SPINLOCK_PREFETCH -#define spin_lock_prefetch(x) prefetchw(x) -#endif - #ifndef PREFETCH_STRIDE #define PREFETCH_STRIDE (4*L1_CACHE_BYTES) #endif -- cgit v1.2.3 From 8e3938cff0191c810b2abd827313c090fe09d166 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 13 Aug 2023 08:37:32 +0000 Subject: platform: mellanox: Fix order in exit flow Fix exit flow order: call mlxplat_post_exit() after mlxplat_i2c_main_exit() in order to unregister main i2c driver before to "mlxplat" driver. Fixes: 0170f616f496 ("platform: mellanox: Split initialization procedure") Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230813083735.39090-2-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 67367f010139..5fb3348023a7 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -6238,8 +6238,6 @@ static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv) if (priv->pdev_mux[i]) platform_device_unregister(priv->pdev_mux[i]); } - - mlxplat_post_exit(); } static int mlxplat_i2c_main_complition_notify(void *handle, int id) @@ -6369,6 +6367,7 @@ static void __exit mlxplat_exit(void) pm_power_off = NULL; mlxplat_pre_exit(priv); mlxplat_i2c_main_exit(priv); + mlxplat_post_exit(); } module_exit(mlxplat_exit); -- cgit v1.2.3 From 3c91d7e8c64f75c63da3565d16d5780320bd5d76 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 13 Aug 2023 08:37:33 +0000 Subject: platform: mellanox: mlx-platform: Fix signals polarity and latch mask Change polarity of chassis health and power signals and fix latch reset mask for L1 switch. Fixes: dd635e33b5c9 ("platform: mellanox: Introduce support of new Nvidia L1 switch") Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230813083735.39090-3-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 5fb3348023a7..69256af04f05 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -237,7 +237,7 @@ #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) -#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5) +#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(6) #define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) #define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4) #define MLXPLAT_CPLD_INTRUSION_MASK BIT(6) @@ -2475,7 +2475,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data), - .inversed = 0, + .inversed = 1, .health = false, }, { @@ -2484,7 +2484,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK, .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data), - .inversed = 0, + .inversed = 1, .health = false, .ind = 8, }, @@ -3677,7 +3677,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { { .label = "latch_reset", .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(5), + .mask = GENMASK(7, 0) & ~BIT(6), .mode = 0200, }, { -- cgit v1.2.3 From 9f8ccdb5088bd03062d9ad9c0f6abf600cbed8e8 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 13 Aug 2023 08:37:34 +0000 Subject: platform: mellanox: mlx-platform: Modify graceful shutdown callback and power down mask Use kernel_power_off() instead of kernel_halt() to pass through machine_power_off() -> pm_power_off(), otherwise axillary power does not go off. Change "power down" bitmask. Fixes: dd635e33b5c9 ("platform: mellanox: Introduce support of new Nvidia L1 switch") Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230813083735.39090-4-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 69256af04f05..240bc3174caf 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -222,7 +222,7 @@ MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) -#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT BIT(4) +#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT GENMASK(5, 4) #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) @@ -2356,7 +2356,7 @@ mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_k u8 action) { dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button"); - kernel_halt(); + kernel_power_off(); return 0; } -- cgit v1.2.3 From d66a8aab7dc36c975bbaa6aa74cf7445878e7c69 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 13 Aug 2023 08:37:35 +0000 Subject: platform: mellanox: Change register offset addresses Move debug register offsets to different location due to hardware changes. Fixes: dd635e33b5c9 ("platform: mellanox: Introduce support of new Nvidia L1 switch") Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230813083735.39090-5-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 240bc3174caf..7d33977d9c60 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -62,10 +62,6 @@ #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b -#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0x3c -#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0x3d -#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0x3e -#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0x3f #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 @@ -126,6 +122,10 @@ #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 +#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0xb6 +#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0xb7 +#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0xb8 +#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0xb9 #define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 #define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 -- cgit v1.2.3 From 2b6aa6610dc9690f79d305ca938abfb799a4f766 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 12 Aug 2023 16:48:18 +0200 Subject: platform/x86: lenovo-ymc: Only bind on machines with a convertible DMI chassis-type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lenovo-ymc driver is causing the keyboard + touchpad to stop working on some regular laptop models such as the Lenovo ThinkBook 13s G2 ITL 20V9. The problem is that there are YMC WMI GUID methods in the ACPI tables of these laptops, despite them not being Yogas and lenovo-ymc loading causes libinput to see a SW_TABLET_MODE switch with state 1. This in turn causes libinput to ignore events from the builtin keyboard and touchpad, since it filters those out for a Yoga in tablet mode. Similar issues with false-positive SW_TABLET_MODE=1 reporting have been seen with the intel-hid driver. Copy the intel-hid driver approach to fix this and only bind to the WMI device on machines where the DMI chassis-type indicates the machine is a convertible. Add a 'force' module parameter to allow overriding the chassis-type check so that users can easily test if the YMC interface works on models which report an unexpected chassis-type. Fixes: e82882cdd241 ("platform/x86: Add driver for Yoga Tablet Mode switch") Link: https://bugzilla.redhat.com/show_bug.cgi?id=2229373 Cc: AndrĂ© Apitzsch Cc: stable@vger.kernel.org Tested-by: Andrew Kallmeyer Tested-by: GergƑ Köteles Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230812144818.383230-1-hdegoede@redhat.com --- drivers/platform/x86/lenovo-ymc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c index 41676188b373..f360370d5002 100644 --- a/drivers/platform/x86/lenovo-ymc.c +++ b/drivers/platform/x86/lenovo-ymc.c @@ -24,6 +24,10 @@ static bool ec_trigger __read_mostly; module_param(ec_trigger, bool, 0444); MODULE_PARM_DESC(ec_trigger, "Enable EC triggering work-around to force emitting tablet mode events"); +static bool force; +module_param(force, bool, 0444); +MODULE_PARM_DESC(force, "Force loading on boards without a convertible DMI chassis-type"); + static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = { { /* Lenovo Yoga 7 14ARB7 */ @@ -35,6 +39,20 @@ static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = { { } }; +static const struct dmi_system_id allowed_chasis_types_dmi_table[] = { + { + .matches = { + DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */), + }, + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" /* Detachable */), + }, + }, + { } +}; + struct lenovo_ymc_private { struct input_dev *input_dev; struct acpi_device *ec_acpi_dev; @@ -111,6 +129,13 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx) struct input_dev *input_dev; int err; + if (!dmi_check_system(allowed_chasis_types_dmi_table)) { + if (force) + dev_info(&wdev->dev, "Force loading Lenovo YMC support\n"); + else + return -ENODEV; + } + ec_trigger |= dmi_check_system(ec_trigger_quirk_dmi_table); priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); -- cgit v1.2.3 From bb6979c5ac592e11b456da728f645c9bea965489 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 11 Aug 2023 18:01:30 +0800 Subject: ASoC: q6dsp: Remove unused declaration Commit 5477518b8a0e ("ASoC: qdsp6: audioreach: add q6apm support") declared but never implemented these. Signed-off-by: Yue Haibing Date: Fri, 11 Aug 2023 19:00:21 +0800 Subject: ASoC: cygnus: Remove unused declarations Commit a6ee05d94e8f ("ASoC: cygnus: Add Cygnus audio DAI driver") declared but never implemented these. Signed-off-by: Yue Haibing Date: Sun, 13 Aug 2023 11:29:55 -0700 Subject: Linux 6.5-rc6 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6bbf9db6b414..00cfb37a9ab8 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 5 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* -- cgit v1.2.3 From 67ed781228bdcca7a0d2058cf62d0c1860898330 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:22 +0800 Subject: ASoC: atmel: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:23 +0800 Subject: ASoC: atmel: tse850-pcm5142: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:24 +0800 Subject: ASoC: sunxi: sun4i-spdif: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:25 +0800 Subject: ASoC: ssm3515: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:26 +0800 Subject: ALSA: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Sat, 12 Aug 2023 21:56:39 +0200 Subject: ASoC: rt1011: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From c7a7f4444b1fd648edc3fb54f2d3822215b46c56 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:40 +0200 Subject: ASoC: rt1015: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 3abc7076851f63c5d193ee9d942554f182527d18 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:41 +0200 Subject: ASoC: rt1015p: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 8a5a8015b1e23e41204738f2147c01bf18039965 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:42 +0200 Subject: ASoC: rt1016: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From e04cbe53205ecfcb1f2a8314dfc829ebbcb542f1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:43 +0200 Subject: ASoC: rt1019: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From ba55dde45b5a5595763af6d06066ab789792e9d3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:44 +0200 Subject: ASoC: rt1305: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include -#include #include #include #include -- cgit v1.2.3 From f36c684e9941b3af6769b984239f62dc9fe99698 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:45 +0200 Subject: ASoC: rt1308: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include -#include #include #include #include -- cgit v1.2.3 From 12ffd88e398cb82f960da25ab990a6864641fee1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:46 +0200 Subject: ASoC: rt5514-spi: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 9fdc4feacdb0a5b3a49d611aff88371f8f8d4971 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:47 +0200 Subject: ASoC: rt5514: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 92f1b48277f2fdaa9649630dc9a8ec298bfd6def Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:48 +0200 Subject: ASoC: rt5645: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 0b759f3b3faa51022752bc4a99ae1af57baf344f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:49 +0200 Subject: ASoC: rt5659: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From b72a4dc2bede787221a4b1b2e3860f6725f109b5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:50 +0200 Subject: ASoC: rt5660: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From 1a625a7a5d74be6b367301e6eb9e38d35797313a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:51 +0200 Subject: ASoC: rt5682-sdw: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include -#include #include #include #include -- cgit v1.2.3 From 797df2a670c336500cdea482f404a24b45b28f45 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:52 +0200 Subject: ASoC: rt715: Drop GPIO includes This driver include two GPIO legacy headers and one contemporary, yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include #include -#include #include -#include #include #include #include -- cgit v1.2.3 From 3e8bcec0787d1a73703c915c31cb00a2fd18ccbf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:50 +0000 Subject: ASoC: soc-dai.h: merge DAI call back functions into ops snd_soc_dai_driver has .ops for call back functions (A), but it also has other call back functions (B). It is duplicated and confusable. struct snd_soc_dai_driver { ... ^ int (*probe)(...); | int (*remove)(...); (B) int (*compress_new)(...); | int (*pcm_new)(...); v ... (A) const struct snd_soc_dai_ops *ops; ... } This patch merges (B) into (A). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8dpb0w6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 13 +++++++++++ sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/soc-core.c | 25 ++++++++++++++++++++ sound/soc/soc-dai.c | 44 ++++++++++++++++++++---------------- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a33d803fe548..85f897fea21a 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -274,6 +274,15 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); struct snd_soc_dai_ops { + /* DAI driver callbacks */ + int (*probe)(struct snd_soc_dai *dai); + int (*remove)(struct snd_soc_dai *dai); + /* compress dai */ + int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); + /* Optional Callback used at pcm creation*/ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); + /* * DAI clocking configuration, all optional. * Called by soc_card drivers, normally in their hw_params. @@ -355,6 +364,10 @@ struct snd_soc_dai_ops { u64 *auto_selectable_formats; int num_auto_selectable_formats; + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; + /* bit field */ unsigned int no_capture_mute:1; }; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0b8258b6bd8e..13693ef9c242 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); if (dai && (dai->component->driver->pcm_construct || - dai->driver->pcm_new)) + (dai->driver->ops && dai->driver->ops->pcm_new))) return true; return false; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a5b96c17633a..7dbf37e0ba2f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,6 +2510,7 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; + struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2538,6 +2539,30 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; + /* REMOVE ME */ + if (dai_drv->probe || + dai_drv->remove || + dai_drv->compress_new || + dai_drv->pcm_new || + dai_drv->probe_order || + dai_drv->remove_order) { + + ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); + if (!ops) + return NULL; + if (dai_drv->ops) + memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); + + ops->probe = dai_drv->probe; + ops->remove = dai_drv->remove; + ops->compress_new = dai_drv->compress_new; + ops->pcm_new = dai_drv->pcm_new; + ops->probe_order = dai_drv->probe_order; + ops->remove_order = dai_drv->remove_order; + + dai_drv->ops = ops; + } + dai->component = component; dai->dev = dev; dai->driver = dai_drv; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 73a97ac6ccb8..3f33f0630ad8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -460,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num) { int ret = -ENOTSUPP; - if (dai->driver->compress_new) - ret = dai->driver->compress_new(rtd, num); + if (dai->driver->ops && + dai->driver->ops->compress_new) + ret = dai->driver->ops->compress_new(rtd, num); return soc_dai_ret(dai, ret); } @@ -545,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->probe_order != order) - continue; - if (dai->probed) continue; - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); + if (dai->driver->ops) { + if (dai->driver->ops->probe_order != order) + continue; - if (ret < 0) - return soc_dai_ret(dai, ret); - } + if (dai->driver->ops->probe) { + int ret = dai->driver->ops->probe(dai); + if (ret < 0) + return soc_dai_ret(dai, ret); + } + } dai->probed = 1; } @@ -570,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order) int i, r, ret = 0; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->remove_order != order) + if (!dai->probed) continue; - if (dai->probed && - dai->driver->remove) { - r = dai->driver->remove(dai); - if (r < 0) - ret = r; /* use last error */ - } + if (dai->driver->ops) { + if (dai->driver->ops->remove_order != order) + continue; + if (dai->driver->ops->remove) { + r = dai->driver->ops->remove(dai); + if (r < 0) + ret = r; /* use last error */ + } + } dai->probed = 0; } @@ -592,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->pcm_new) { - int ret = dai->driver->pcm_new(rtd, dai); + if (dai->driver->ops && + dai->driver->ops->pcm_new) { + int ret = dai->driver->ops->pcm_new(rtd, dai); if (ret < 0) return soc_dai_ret(dai, ret); } -- cgit v1.2.3 From c64f5bd3afa0bf7a3b550bb63b9a5644acb04404 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:59 +0000 Subject: ASoC: ti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt9b0vw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 22 +++++++++++----------- sound/soc/ti/davinci-mcasp.c | 27 +++++++++++++-------------- sound/soc/ti/omap-dmic.c | 22 +++++++++++----------- sound/soc/ti/omap-mcbsp.c | 28 ++++++++++++++-------------- sound/soc/ti/omap-mcpdm.c | 22 +++++++++++----------- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 97dd1634b6be..07c8b2259208 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .shutdown = davinci_i2s_shutdown, - .prepare = davinci_i2s_prepare, - .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, - .set_fmt = davinci_i2s_set_dai_fmt, - .set_clkdiv = davinci_i2s_dai_set_clkdiv, - -}; - static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .probe = davinci_i2s_dai_probe, + .shutdown = davinci_i2s_shutdown, + .prepare = davinci_i2s_prepare, + .trigger = davinci_i2s_trigger, + .hw_params = davinci_i2s_hw_params, + .set_fmt = davinci_i2s_set_dai_fmt, + .set_clkdiv = davinci_i2s_dai_set_clkdiv, + +}; + static struct snd_soc_dai_driver davinci_i2s_dai = { - .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 172fea764a31..7e7d665a5504 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, } } -static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, - .shutdown = davinci_mcasp_shutdown, - .trigger = davinci_mcasp_trigger, - .delay = davinci_mcasp_delay, - .hw_params = davinci_mcasp_hw_params, - .set_fmt = davinci_mcasp_set_dai_fmt, - .set_clkdiv = davinci_mcasp_set_clkdiv, - .set_sysclk = davinci_mcasp_set_sysclk, - .set_tdm_slot = davinci_mcasp_set_tdm_slot, -}; - static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .probe = davinci_mcasp_dai_probe, + .startup = davinci_mcasp_startup, + .shutdown = davinci_mcasp_shutdown, + .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, + .hw_params = davinci_mcasp_hw_params, + .set_fmt = davinci_mcasp_set_dai_fmt, + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, + .set_tdm_slot = davinci_mcasp_set_tdm_slot, +}; + #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "IIS Playback", .channels_min = 1, @@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "DIT Playback", .channels_min = 1, diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index cb60af36dbc3..5b5eccf303ab 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } -static const struct snd_soc_dai_ops omap_dmic_dai_ops = { - .startup = omap_dmic_dai_startup, - .shutdown = omap_dmic_dai_shutdown, - .hw_params = omap_dmic_dai_hw_params, - .prepare = omap_dmic_dai_prepare, - .trigger = omap_dmic_dai_trigger, - .set_sysclk = omap_dmic_set_dai_sysclk, -}; - static int omap_dmic_probe(struct snd_soc_dai *dai) { struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); @@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_dmic_dai_ops = { + .probe = omap_dmic_probe, + .remove = omap_dmic_remove, + .startup = omap_dmic_dai_startup, + .shutdown = omap_dmic_dai_shutdown, + .hw_params = omap_dmic_dai_hw_params, + .prepare = omap_dmic_dai_prepare, + .trigger = omap_dmic_dai_trigger, + .set_sysclk = omap_dmic_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_dmic_dai = { .name = "omap-dmic", - .probe = omap_dmic_probe, - .remove = omap_dmic_remove, .capture = { .channels_min = 2, .channels_max = 6, diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index f9fe96b61852..fdabed5133e8 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -static const struct snd_soc_dai_ops mcbsp_dai_ops = { - .startup = omap_mcbsp_dai_startup, - .shutdown = omap_mcbsp_dai_shutdown, - .prepare = omap_mcbsp_dai_prepare, - .trigger = omap_mcbsp_dai_trigger, - .delay = omap_mcbsp_dai_delay, - .hw_params = omap_mcbsp_dai_hw_params, - .set_fmt = omap_mcbsp_dai_set_dai_fmt, - .set_clkdiv = omap_mcbsp_dai_set_clkdiv, - .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, -}; - static int omap_mcbsp_probe(struct snd_soc_dai *dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); @@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mcbsp_dai_ops = { + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, + .startup = omap_mcbsp_dai_startup, + .shutdown = omap_mcbsp_dai_shutdown, + .prepare = omap_mcbsp_dai_prepare, + .trigger = omap_mcbsp_dai_trigger, + .delay = omap_mcbsp_dai_delay, + .hw_params = omap_mcbsp_dai_hw_params, + .set_fmt = omap_mcbsp_dai_set_dai_fmt, + .set_clkdiv = omap_mcbsp_dai_set_clkdiv, + .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = omap_mcbsp_probe, - .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 35deceb73427..d7d9f708f1fd 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { - .startup = omap_mcpdm_dai_startup, - .shutdown = omap_mcpdm_dai_shutdown, - .hw_params = omap_mcpdm_dai_hw_params, - .prepare = omap_mcpdm_prepare, -}; - static int omap_mcpdm_probe(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); @@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { + .probe = omap_mcpdm_probe, + .remove = omap_mcpdm_remove, + .startup = omap_mcpdm_dai_startup, + .shutdown = omap_mcpdm_dai_shutdown, + .hw_params = omap_mcpdm_dai_hw_params, + .prepare = omap_mcpdm_prepare, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, +}; + #ifdef CONFIG_PM_SLEEP static int omap_mcpdm_suspend(struct snd_soc_component *component) { @@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component) #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_probe, - .remove = omap_mcpdm_remove, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .remove_order = SND_SOC_COMP_ORDER_EARLY, .playback = { .channels_min = 1, .channels_max = 5, -- cgit v1.2.3 From edd89ceac2e43bf1bf612fe63682b07a60f16a62 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:06 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sf8tb0vp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index d5b6f5187f8e..7b2563075743 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axi_i2s_dai_ops = { + .probe = axi_i2s_dai_probe, .startup = axi_i2s_startup, .shutdown = axi_i2s_shutdown, .trigger = axi_i2s_trigger, @@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = { }; static struct snd_soc_dai_driver axi_i2s_dai = { - .probe = axi_i2s_dai_probe, .ops = &axi_i2s_dai_ops, .symmetric_rate = 1, }; -- cgit v1.2.3 From db49eb7b3855cc9bd422663b1cd84a36f5bd8d1f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:15 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0odb0vg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index e4c99bbc9cdd..10545bd99704 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops axi_spdif_dai_ops = { + .probe = axi_spdif_dai_probe, .startup = axi_spdif_startup, .shutdown = axi_spdif_shutdown, .trigger = axi_spdif_trigger, @@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = { }; static struct snd_soc_dai_driver axi_spdif_dai = { - .probe = axi_spdif_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From d86eb53532362f738dd840d7b953b2a769ccdd4b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:21 +0000 Subject: ASoC: amd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3xb0va.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 24 ++++++++++++------------ sound/soc/amd/acp/acp-rembrandt.c | 3 --- sound/soc/amd/acp/acp-renoir.c | 2 -- sound/soc/amd/acp/amd.h | 1 - 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 09dc5f2c0bfc..df350014966a 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -539,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .startup = acp_i2s_startup, - .hw_params = acp_i2s_hwparams, - .prepare = acp_i2s_prepare, - .trigger = acp_i2s_trigger, - .set_fmt = acp_i2s_set_fmt, - .set_tdm_slot = acp_i2s_set_tdm_slot, -}; -EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); - -int asoc_acp_i2s_probe(struct snd_soc_dai *dai) +static int acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); @@ -569,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON); + +const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { + .probe = acp_i2s_probe, + .startup = acp_i2s_startup, + .hw_params = acp_i2s_hwparams, + .prepare = acp_i2s_prepare, + .trigger = acp_i2s_trigger, + .set_fmt = acp_i2s_set_fmt, + .set_tdm_slot = acp_i2s_set_tdm_slot, +}; +EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index cc8284f417c0..1bf7b2e68a11 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -98,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -124,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-hs", @@ -150,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 1899658ab25d..54235cad9cc9 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -97,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -123,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 2ebe2099cbb5..d6cfae6ec5f7 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -198,7 +198,6 @@ union acp_i2stdm_mstrclkgen { extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; -int asoc_acp_i2s_probe(struct snd_soc_dai *dai); int acp_platform_register(struct device *dev); int acp_platform_unregister(struct device *dev); -- cgit v1.2.3 From 2c88ba731fec284af52ed19b6c6eaacffb0c50f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:27 +0000 Subject: ASoC: dwc: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Maxim Kochetkov Link: https://lore.kernel.org/r/87o7jhb0v4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 1f1ee14b04e6..0a4698008d64 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -443,7 +443,16 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask return 0; } +static int dw_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); + return 0; +} + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .probe = dw_i2s_dai_probe, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, @@ -680,14 +689,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } -static int dw_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); - return 0; -} - static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; @@ -706,7 +707,6 @@ static int dw_i2s_probe(struct platform_device *pdev) return -ENOMEM; dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->probe = dw_i2s_dai_probe; dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->i2s_base)) -- cgit v1.2.3 From 98e268a7205706f809658345399eead7c7d1b8bb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:41 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87msz1b0uq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index a1ed141b8795..abfaf3cdf5bb 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { + .probe = mmp_sspa_probe, .startup = mmp_sspa_startup, .shutdown = mmp_sspa_shutdown, .trigger = mmp_sspa_trigger, @@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { }; static struct snd_soc_dai_driver mmp_sspa_dai = { - .probe = mmp_sspa_probe, .playback = { .channels_min = 1, .channels_max = 128, -- cgit v1.2.3 From 59cd0ba842771946e922291199ce8c7a662484d4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:47 +0000 Subject: ASoC: bcm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leelb0uk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 85f705afcdbb..9bda6499e66e 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream, bcm2835_i2s_stop_clock(dev); } +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, + &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], + &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); + + return 0; +} + static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { + .probe = bcm2835_i2s_dai_probe, .startup = bcm2835_i2s_startup, .shutdown = bcm2835_i2s_shutdown, .prepare = bcm2835_i2s_prepare, @@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, }; -static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, - &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return 0; -} - static struct snd_soc_dai_driver bcm2835_i2s_dai = { .name = "bcm2835-i2s", - .probe = bcm2835_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 5e5f68ca836e740c1d788f04efa84b37ed185606 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:53 +0000 Subject: ASoC: fsl: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu5b0ue.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_aud2htx.c | 10 +++++----- sound/soc/fsl/fsl_easrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_esai.c | 20 ++++++++++---------- sound/soc/fsl/fsl_micfil.c | 14 +++++++------- sound/soc/fsl/fsl_sai.c | 24 ++++++++++++------------ sound/soc/fsl/fsl_spdif.c | 17 ++++++++--------- sound/soc/fsl/fsl_ssi.c | 3 +-- sound/soc/fsl/fsl_xcvr.c | 16 ++++++++-------- 9 files changed, 67 insertions(+), 69 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index adb8a59de2bd..b793263291dc 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { - .startup = fsl_asrc_dai_startup, - .hw_params = fsl_asrc_dai_hw_params, - .hw_free = fsl_asrc_dai_hw_free, - .trigger = fsl_asrc_dai_trigger, -}; - static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) { struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); @@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .probe = fsl_asrc_dai_probe, + .startup = fsl_asrc_dai_startup, + .hw_params = fsl_asrc_dai_hw_params, + .hw_free = fsl_asrc_dai_hw_free, + .trigger = fsl_asrc_dai_trigger, +}; + #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_3LE) static struct snd_soc_dai_driver fsl_asrc_dai = { - .probe = fsl_asrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 46b0c5dcc4a5..fc56f6ade368 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { - .trigger = fsl_aud2htx_trigger, -}; - static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev); @@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { + .probe = fsl_aud2htx_dai_probe, + .trigger = fsl_aud2htx_trigger, +}; + static struct snd_soc_dai_driver fsl_aud2htx_dai = { - .probe = fsl_aud2htx_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 670cbdb361b6..ba62995c909a 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { - .startup = fsl_easrc_startup, - .trigger = fsl_easrc_trigger, - .hw_params = fsl_easrc_hw_params, - .hw_free = fsl_easrc_hw_free, -}; - static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); @@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { + .probe = fsl_easrc_dai_probe, + .startup = fsl_easrc_startup, + .trigger = fsl_easrc_trigger, + .hw_params = fsl_easrc_hw_params, + .hw_free = fsl_easrc_hw_free, +}; + static struct snd_soc_dai_driver fsl_easrc_dai = { - .probe = fsl_easrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 936f0cd4b06d..d0d8a01da9bd 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_esai_dai_ops = { - .startup = fsl_esai_startup, - .trigger = fsl_esai_trigger, - .hw_params = fsl_esai_hw_params, - .set_sysclk = fsl_esai_set_dai_sysclk, - .set_fmt = fsl_esai_set_dai_fmt, - .set_tdm_slot = fsl_esai_set_dai_tdm_slot, -}; - static int fsl_esai_dai_probe(struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); @@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_esai_dai_ops = { + .probe = fsl_esai_dai_probe, + .startup = fsl_esai_startup, + .trigger = fsl_esai_trigger, + .hw_params = fsl_esai_hw_params, + .set_sysclk = fsl_esai_set_dai_sysclk, + .set_fmt = fsl_esai_set_dai_fmt, + .set_tdm_slot = fsl_esai_set_dai_tdm_slot, +}; + static struct snd_soc_dai_driver fsl_esai_dai = { - .probe = fsl_esai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index bbaad6ec2e72..0d37edb70261 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -764,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { - .startup = fsl_micfil_startup, - .trigger = fsl_micfil_trigger, - .hw_params = fsl_micfil_hw_params, -}; - static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -807,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .probe = fsl_micfil_dai_probe, + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, +}; + static struct snd_soc_dai_driver fsl_micfil_dai = { - .probe = fsl_micfil_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index f7676d30c82f..1e4020fae05a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { - .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, - .set_sysclk = fsl_sai_set_dai_sysclk, - .set_fmt = fsl_sai_set_dai_fmt, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, - .hw_params = fsl_sai_hw_params, - .hw_free = fsl_sai_hw_free, - .trigger = fsl_sai_trigger, - .startup = fsl_sai_startup, -}; - static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); @@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { + .probe = fsl_sai_dai_probe, + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, + .set_sysclk = fsl_sai_set_dai_sysclk, + .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .hw_params = fsl_sai_hw_params, + .hw_free = fsl_sai_hw_free, + .trigger = fsl_sai_trigger, + .startup = fsl_sai_startup, +}; + static int fsl_sai_dai_resume(struct snd_soc_component *component) { struct fsl_sai *sai = snd_soc_component_get_drvdata(component); @@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) } static struct snd_soc_dai_driver fsl_sai_dai_template = { - .probe = fsl_sai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 95bb8b10494a..78d9dfbe6548 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -765,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { - .startup = fsl_spdif_startup, - .hw_params = fsl_spdif_hw_params, - .trigger = fsl_spdif_trigger, - .shutdown = fsl_spdif_shutdown, -}; - - /* * FSL SPDIF IEC958 controller(mixer) functions * @@ -1283,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { + .probe = fsl_spdif_dai_probe, + .startup = fsl_spdif_startup, + .hw_params = fsl_spdif_hw_params, + .trigger = fsl_spdif_trigger, + .shutdown = fsl_spdif_shutdown, +}; + static struct snd_soc_dai_driver fsl_spdif_dai = { - .probe = &fsl_spdif_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 53ed3701b0b0..079ac04272b8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { + .probe = fsl_ssi_dai_probe, .startup = fsl_ssi_startup, .shutdown = fsl_ssi_shutdown, .hw_params = fsl_ssi_hw_params, @@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { }; static struct snd_soc_dai_driver fsl_ssi_dai_template = { - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, @@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .symmetric_channels = 1, - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU AC97 Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 318fe77683f5..fa0a15263c66 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { }, }; -static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { - .prepare = fsl_xcvr_prepare, - .startup = fsl_xcvr_startup, - .shutdown = fsl_xcvr_shutdown, - .trigger = fsl_xcvr_trigger, -}; - static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); @@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { + .probe = fsl_xcvr_dai_probe, + .prepare = fsl_xcvr_prepare, + .startup = fsl_xcvr_startup, + .shutdown = fsl_xcvr_shutdown, + .trigger = fsl_xcvr_trigger, +}; + static struct snd_soc_dai_driver fsl_xcvr_dai = { - .probe = fsl_xcvr_dai_probe, .ops = &fsl_xcvr_dai_ops, .playback = { .stream_name = "CPU-Playback", -- cgit v1.2.3 From a98bd9e1173872cdbfc3ca7a2c43382f1417ab7e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:59 +0000 Subject: ASoC: img: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9pb0u8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/img/img-i2s-in.c | 14 +++++++------- sound/soc/img/img-i2s-out.c | 14 +++++++------- sound/soc/img/img-parallel-out.c | 14 +++++++------- sound/soc/img/img-spdif-in.c | 12 ++++++------ sound/soc/img/img-spdif-out.c | 12 ++++++------ 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index b7ab8467b5cf..b6b6339c164b 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { - .trigger = img_i2s_in_trigger, - .hw_params = img_i2s_in_hw_params, - .set_fmt = img_i2s_in_set_fmt -}; - static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); @@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .probe = img_i2s_in_dai_probe, + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_in_component = { .name = "img-i2s-in", .legacy_dai_naming = 1, @@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; i2s->dma_data.addr_width = 4; - i2s->dai_driver.probe = img_i2s_in_dai_probe; i2s->dai_driver.capture.channels_min = 2; i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index fe95ddfb8407..41ea5ba52181 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { - .trigger = img_i2s_out_trigger, - .hw_params = img_i2s_out_hw_params, - .set_fmt = img_i2s_out_set_fmt -}; - static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); @@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .probe = img_i2s_out_dai_probe, + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_out_component = { .name = "img-i2s-out", .legacy_dai_naming = 1, @@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->dma_data.addr_width = 4; i2s->dma_data.maxburst = 4; - i2s->dai_driver.probe = img_i2s_out_dai_probe; i2s->dai_driver.playback.channels_min = 2; i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index df1291ee2b3b..815e68a7048c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_prl_out_dai_ops = { - .trigger = img_prl_out_trigger, - .hw_params = img_prl_out_hw_params, - .set_fmt = img_prl_out_set_fmt -}; - static int img_prl_out_dai_probe(struct snd_soc_dai *dai) { struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); @@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .probe = img_prl_out_dai_probe, + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + static struct snd_soc_dai_driver img_prl_out_dai = { - .probe = img_prl_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 558062a1804a..9646e9d3f0bc 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, return img_spdif_in_do_clkgen_single(spdif, rate); } -static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { - .trigger = img_spdif_in_trigger, - .hw_params = img_spdif_in_hw_params -}; - static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); @@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .probe = img_spdif_in_dai_probe, + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + static struct snd_soc_dai_driver img_spdif_in_dai = { - .probe = img_spdif_in_dai_probe, .capture = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index b13e128e50d6..dfa72afa946e 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { - .trigger = img_spdif_out_trigger, - .hw_params = img_spdif_out_hw_params -}; - static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); @@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .probe = img_spdif_out_dai_probe, + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + static struct snd_soc_dai_driver img_spdif_out_dai = { - .probe = img_spdif_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From f522af4cbe0158de3f518ed76b328ea6297a52b2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:05 +0000 Subject: ASoC: sof: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6p9b0u2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 5530b5d793d0..740b637822db 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = { .owner = THIS_MODULE, }; +static const struct snd_soc_dai_ops sof_probes_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver sof_probes_dai_drv[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, + .ops = &sof_probes_dai_ops, .cops = &sof_probes_compr_ops, .capture = { .stream_name = "Probe Extraction", -- cgit v1.2.3 From f33b8df2233a8f7007a289e4cf1bfce403fa6bf0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:11 +0000 Subject: ASoC: sti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4tb0tw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index a4d74d1e3c24..2c21a86421e6 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) return sti_uniperiph_dai_create_ctrl(dai); } -static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { +static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = { .probe = sti_uniperiph_dai_probe, }; +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .ops = &sti_uniperiph_dai_ops, +}; + static const struct snd_soc_component_driver sti_uniperiph_dai_component = { .name = "sti_cpu_dai", .suspend = sti_uniperiph_suspend, -- cgit v1.2.3 From 2fb00b84cdb7dd2a8fe0d584236990b2392c5a57 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:17 +0000 Subject: ASoC: stm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkdb0tq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 2 +- sound/soc/stm/stm32_sai_sub.c | 18 ++++++++++++++---- sound/soc/stm/stm32_spdifrx.c | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 387130701960..06a42130f5e4 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { }; static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { + .probe = stm32_i2s_dai_probe, .set_sysclk = stm32_i2s_set_sysclk, .set_fmt = stm32_i2s_set_dai_fmt, .startup = stm32_i2s_startup, @@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; - dai_ptr->probe = stm32_i2s_dai_probe; dai_ptr->ops = &stm32_i2s_pcm_dai_ops; dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 271ec5b3378d..42d67b7a68e8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) } static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { + .probe = stm32_sai_dai_probe, + .set_sysclk = stm32_sai_set_sysclk, + .set_fmt = stm32_sai_set_dai_fmt, + .set_tdm_slot = stm32_sai_set_dai_tdm_slot, + .startup = stm32_sai_startup, + .hw_params = stm32_sai_hw_params, + .trigger = stm32_sai_trigger, + .shutdown = stm32_sai_shutdown, + .pcm_new = stm32_sai_pcm_new, +}; + +static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = { + .probe = stm32_sai_dai_probe, .set_sysclk = stm32_sai_set_sysclk, .set_fmt = stm32_sai_set_dai_fmt, .set_tdm_slot = stm32_sai_set_dai_tdm_slot, @@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = { }; static struct snd_soc_dai_driver stm32_sai_playback_dai = { - .probe = stm32_sai_dai_probe, - .pcm_new = stm32_sai_pcm_new, .id = 1, /* avoid call to fmt_single_name() */ .playback = { .channels_min = 1, @@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { }; static struct snd_soc_dai_driver stm32_sai_capture_dai = { - .probe = stm32_sai_dai_probe, .id = 1, /* avoid call to fmt_single_name() */ .capture = { .channels_min = 1, @@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &stm32_sai_pcm_dai_ops, + .ops = &stm32_sai_pcm_dai_ops2, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index a4066f271f2d..a359b528b26b 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { + .probe = stm32_spdifrx_dai_probe, .startup = stm32_spdifrx_startup, .hw_params = stm32_spdifrx_hw_params, .trigger = stm32_spdifrx_trigger, @@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { { - .probe = stm32_spdifrx_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, -- cgit v1.2.3 From 208b8395f79e4ad9196849b744f6e4a7abd2b836 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:22 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzxb0tl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d19769dde139..b70034c07eee 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -813,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, .startup = pxa_ssp_startup, .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, @@ -824,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { }; static struct snd_soc_dai_driver pxa_ssp_dai = { - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, .playback = { .channels_min = 1, .channels_max = 8, -- cgit v1.2.3 From 47ca9f546ef6806925077e5ea6e084af660ee41b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:28 +0000 Subject: ASoC: rsnd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkfhb0tg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cf2031b7e209..e29c2fee9521 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) @@ -1355,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, return 0; } -static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); int ret; @@ -1382,6 +1370,18 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .pcm_new = rsnd_soc_dai_pcm_new, + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, + .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), +}; + static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, struct device_node *node_np, @@ -1411,7 +1411,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; - drv->pcm_new = rsnd_pcm_new; drv->id = dai_i; drv->dai_args = &rdai->dai_args; -- cgit v1.2.3 From 9174fd60e55d7ff1ad2c909c67de48ebe7008e5a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:34 +0000 Subject: ASoC: qcom: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a5v1b0ta.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 4 -- sound/soc/qcom/lpass-cpu.c | 40 +++++++++------ sound/soc/qcom/lpass-ipq806x.c | 1 - sound/soc/qcom/lpass-sc7180.c | 5 +- sound/soc/qcom/lpass-sc7280.c | 2 - sound/soc/qcom/lpass.h | 4 +- sound/soc/qcom/qdsp6/q6afe-dai.c | 88 +++++++++++++++++--------------- sound/soc/qcom/qdsp6/q6asm-dai.c | 6 ++- sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c | 3 -- 9 files changed, 80 insertions(+), 73 deletions(-) diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index abaf694ee9a3..f919d46e18ca 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_SECONDARY] = { @@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_TERTIARY] = { @@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_QUATERNARY] = { @@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, }; diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index dbdaaa85ce48..39571fed4001 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { - .set_sysclk = lpass_cpu_daiops_set_sysclk, - .startup = lpass_cpu_daiops_startup, - .shutdown = lpass_cpu_daiops_shutdown, - .hw_params = lpass_cpu_daiops_hw_params, - .trigger = lpass_cpu_daiops_trigger, - .prepare = lpass_cpu_daiops_prepare, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); - -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { int ret; struct snd_soc_dai_driver *drv = dai->driver; @@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } -EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) +static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; @@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) return ret; } -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = { + .pcm_new = lpass_cpu_daiops_pcm_new, + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2); static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index ef8a7984f232..2c97f295e394 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 56db852f4eab..d16c0d83aaad 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, - .ops = &asoc_qcom_lpass_cpu_dai_ops, - .pcm_new = lpass_cpu_pcm_new, + .ops = &asoc_qcom_lpass_cpu_dai_ops2, }, { .id = LPASS_DP_RX, .name = "Hdmi", diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index bcf18fe8e14d..6b2eb25ed939 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = LPASS_DP_RX, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index dd78600fc7b0..bdfe66ec3314 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2; extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops; #endif /* __LPASS_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index dbff55a97162..3faa7e0eb0dd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, }; -static const struct snd_soc_dai_ops q6hdmi_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6hdmi_hw_params, - .shutdown = q6afe_dai_shutdown, -}; - -static const struct snd_soc_dai_ops q6i2s_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6i2s_hw_params, - .set_fmt = q6i2s_set_fmt, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, -}; - -static const struct snd_soc_dai_ops q6slim_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6slim_hw_params, - .shutdown = q6afe_dai_shutdown, - .set_channel_map = q6slim_set_channel_map, -}; - -static const struct snd_soc_dai_ops q6tdm_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_tdm_slot = q6tdm_set_tdm_slot, - .set_channel_map = q6tdm_set_channel_map, - .hw_params = q6tdm_hw_params, -}; - -static const struct snd_soc_dai_ops q6dma_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_channel_map = q6dma_set_channel_map, - .hw_params = q6dma_hw_params, -}; - static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops q6hdmi_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static const struct snd_soc_dai_ops q6i2s_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static const struct snd_soc_dai_ops q6slim_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static const struct snd_soc_dai_ops q6tdm_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_tdm_slot = q6tdm_set_tdm_slot, + .set_channel_map = q6tdm_set_channel_map, + .hw_params = q6tdm_hw_params, +}; + +static const struct snd_soc_dai_ops q6dma_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, +}; + static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev) dev_set_drvdata(dev, dai_data); of_q6afe_parse_dai_data(dev, dai_data); - cfg.probe = msm_dai_q6_dai_probe; - cfg.remove = msm_dai_q6_dai_remove; cfg.q6hdmi_ops = &q6hdmi_ops; cfg.q6slim_ops = &q6slim_ops; cfg.q6i2s_ops = &q6i2s_ops; diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 5fc8088e63c8..fe0666e9fd23 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = { Q6ASM_FEDAI_DRIVER(8), }; +static const struct snd_soc_dai_ops q6asm_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int of_q6asm_parse_dai_data(struct device *dev, struct q6asm_dai_data *pdata) { @@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev, dai_drv->playback = empty_stream; if (of_property_read_bool(node, "is-compress-dai")) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &q6asm_dai_ops; } return 0; diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index ac937a6bf909..4919001de08b 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, int i; for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) { - q6dsp_audio_fe_dais[i].probe = cfg->probe; - q6dsp_audio_fe_dais[i].remove = cfg->remove; - switch (q6dsp_audio_fe_dais[i].id) { case HDMI_RX: case DISPLAY_PORT_RX: -- cgit v1.2.3 From 4fc3331cb5f93b5a5ed5ee153b442960d11e1049 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:41 +0000 Subject: ASoC: au1x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ralb0t3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/ac97c.c | 10 +++++----- sound/soc/au1x/psc-ac97.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index a11d6841afc2..b0e1a1253e10 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops alchemy_ac97c_ops = { - .startup = alchemy_ac97c_startup, -}; - static int au1xac97c_dai_probe(struct snd_soc_dai *dai) { return ac97c_workdata ? 0 : -ENODEV; } +static const struct snd_soc_dai_ops alchemy_ac97c_ops = { + .probe = au1xac97c_dai_probe, + .startup = alchemy_ac97c_startup, +}; + static struct snd_soc_dai_driver au1xac97c_dai_driver = { .name = "alchemy-ac97c", - .probe = au1xac97c_dai_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 9fd91aea7d1a..5d50ebc2bdd5 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .probe = au1xpsc_ac97_probe, .startup = au1xpsc_ac97_startup, .trigger = au1xpsc_ac97_trigger, .hw_params = au1xpsc_ac97_hw_params, }; static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { - .probe = au1xpsc_ac97_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, -- cgit v1.2.3 From 2870ffb31c58a301417ee12151122b337b316d0a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:46 +0000 Subject: ASoC: ux500: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Linus Walleij Link: https://lore.kernel.org/r/877cq5b0sx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 44e88dad8584..cde0dd8e2569 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { { + .probe = ux500_msp_dai_of_probe, .set_sysclk = ux500_msp_dai_set_dai_sysclk, .set_fmt = ux500_msp_dai_set_dai_fmt, .set_tdm_slot = ux500_msp_dai_set_tdm_slot, @@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { }; static struct snd_soc_dai_driver ux500_msp_dai_drv = { - .probe = ux500_msp_dai_of_probe, .playback.channels_min = UX500_MSP_MIN_CHANNELS, .playback.channels_max = UX500_MSP_MAX_CHANNELS, .playback.rates = UX500_I2S_RATES, -- cgit v1.2.3 From 331cd4d326244d853eb2e9fd3dcf55969055187e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:52 +0000 Subject: ASoC: sunxi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/875y5pb0sr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 6 +++++- sound/soc/sunxi/sun4i-i2s.c | 18 +++++++++--------- sound/soc/sunxi/sun4i-spdif.c | 2 +- sound/soc/sunxi/sun50i-dmic.c | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 55328850aef5..f0a5fd901101 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops dummy_dai_ops = { + .probe = sun4i_codec_dai_probe, +}; + static struct snd_soc_dai_driver dummy_cpu_dai = { .name = "sun4i-codec-cpu-dai", - .probe = sun4i_codec_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .ops = &dummy_dai_ops, }; static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 669d712bbe9f..5124b6c9ceb4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, return 0; } -static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { - .hw_params = sun4i_i2s_hw_params, - .set_fmt = sun4i_i2s_set_fmt, - .set_sysclk = sun4i_i2s_set_sysclk, - .set_tdm_slot = sun4i_i2s_set_tdm_slot, - .trigger = sun4i_i2s_trigger, -}; - static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { + .probe = sun4i_i2s_dai_probe, + .hw_params = sun4i_i2s_hw_params, + .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, + .trigger = sun4i_i2s_trigger, +}; + #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver sun4i_i2s_dai = { - .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index c2b55d2e5fe1..b849bb7cf58e 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = { + .probe = sun4i_spdif_soc_dai_probe, .startup = sun4i_spdif_startup, .trigger = sun4i_spdif_trigger, .hw_params = sun4i_spdif_hw_params, @@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { .rates = SUN4I_RATES, .formats = SUN4I_FORMATS, }, - .probe = sun4i_spdif_soc_dai_probe, .ops = &sun4i_spdif_dai_ops, .name = "spdif", }; diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index c10439b9e0a2..2599683a582d 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = { + .probe = sun50i_dmic_soc_dai_probe, .startup = sun50i_dmic_startup, .trigger = sun50i_dmic_trigger, .hw_params = sun50i_dmic_hw_params, @@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = { .formats = SUN50I_DMIC_FORMATS, .sig_bits = 21, }, - .probe = sun50i_dmic_soc_dai_probe, .ops = &sun50i_dmic_dai_ops, .name = "dmic", }; -- cgit v1.2.3 From b36e672b6b6fa4f68fc74c3b85ba9b4a615fc1d9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:58 +0000 Subject: ASoC: tegra: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874jl9b0sl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 10 +++++----- sound/soc/tegra/tegra20_i2s.c | 2 +- sound/soc/tegra/tegra20_spdif.c | 2 +- sound/soc/tegra/tegra210_admaif.c | 12 ++++++------ sound/soc/tegra/tegra30_i2s.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 60e7df41c64c..e713feca25fa 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { - .trigger = tegra20_ac97_trigger, -}; - static int tegra20_ac97_probe(struct snd_soc_dai *dai) { struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); @@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { + .probe = tegra20_ac97_probe, + .trigger = tegra20_ac97_trigger, +}; + static struct snd_soc_dai_driver tegra20_ac97_dai = { .name = "tegra-ac97-pcm", - .probe = tegra20_ac97_probe, .playback = { .stream_name = "PCM Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index d38b58305c6b..f11618e8f13e 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { + .probe = tegra20_i2s_probe, .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, .trigger = tegra20_i2s_trigger, @@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { - .probe = tegra20_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index d034803695a0..b0670aa4d967 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { + .probe = tegra20_spdif_probe, .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, .startup = tegra20_spdif_startup, @@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { static struct snd_soc_dai_driver tegra20_spdif_dai = { .name = "tegra20-spdif", - .probe = tegra20_spdif_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 6868508585a0..9f9334e48049 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, } } -static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { - .hw_params = tegra_admaif_hw_params, - .trigger = tegra_admaif_trigger, -}; - static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { + .probe = tegra_admaif_dai_probe, + .hw_params = tegra_admaif_hw_params, + .trigger = tegra_admaif_trigger, +}; + #define DAI(dai_name) \ { \ .name = dai_name, \ - .probe = tegra_admaif_dai_probe, \ .playback = { \ .stream_name = dai_name " Playback", \ .channels_min = 1, \ diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 644280603095..81eaece51130 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { + .probe = tegra30_i2s_probe, .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, @@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { - .probe = tegra30_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 2e85e70608c5d7233244c19ec2253dd1acb01e17 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:04 +0000 Subject: ASoC: atmel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87350tb0sg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 16 ++++++++-------- sound/soc/atmel/mchp-i2s-mcc.c | 24 ++++++++++++------------ sound/soc/atmel/mchp-pdmc.c | 18 +++++++++--------- sound/soc/atmel/mchp-spdifrx.c | 14 +++++++------- sound/soc/atmel/mchp-spdiftx.c | 18 +++++++++--------- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 4febd4d3d0fa..6c20c643f321 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return err; } -static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { - .prepare = atmel_i2s_prepare, - .trigger = atmel_i2s_trigger, - .hw_params = atmel_i2s_hw_params, - .set_fmt = atmel_i2s_set_dai_fmt, -}; - static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) { struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { + .probe = atmel_i2s_dai_probe, + .prepare = atmel_i2s_prepare, + .trigger = atmel_i2s_trigger, + .hw_params = atmel_i2s_hw_params, + .set_fmt = atmel_i2s_set_dai_fmt, +}; + static struct snd_soc_dai_driver atmel_i2s_dai = { - .probe = atmel_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 4b8a63295f89..25ed0b953bfd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .set_sysclk = mchp_i2s_mcc_set_sysclk, - .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, - .startup = mchp_i2s_mcc_startup, - .trigger = mchp_i2s_mcc_trigger, - .hw_params = mchp_i2s_mcc_hw_params, - .hw_free = mchp_i2s_mcc_hw_free, - .set_fmt = mchp_i2s_mcc_set_dai_fmt, - .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, -}; - static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) { struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { + .probe = mchp_i2s_mcc_dai_probe, + .set_sysclk = mchp_i2s_mcc_set_sysclk, + .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, + .startup = mchp_i2s_mcc_startup, + .trigger = mchp_i2s_mcc_trigger, + .hw_params = mchp_i2s_mcc_hw_params, + .hw_free = mchp_i2s_mcc_hw_free, + .set_fmt = mchp_i2s_mcc_set_dai_fmt, + .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, +}; + #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { - .probe = mchp_i2s_mcc_dai_probe, .playback = { .stream_name = "I2SMCC-Playback", .channels_min = 1, diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index c79c73e6791e..944d78ef2f36 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -706,13 +706,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .set_fmt = mchp_pdmc_set_fmt, - .startup = mchp_pdmc_startup, - .hw_params = mchp_pdmc_hw_params, - .trigger = mchp_pdmc_trigger, -}; - static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd) { struct mchp_pdmc_chmap *info; @@ -765,8 +758,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, return ret; } +static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { + .probe = mchp_pdmc_dai_probe, + .set_fmt = mchp_pdmc_set_fmt, + .startup = mchp_pdmc_startup, + .hw_params = mchp_pdmc_hw_params, + .trigger = mchp_pdmc_trigger, + .pcm_new = &mchp_pdmc_pcm_new, +}; + static struct snd_soc_dai_driver mchp_pdmc_dai = { - .probe = mchp_pdmc_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -777,7 +778,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, .ops = &mchp_pdmc_dai_ops, - .pcm_new = &mchp_pdmc_pcm_new, }; /* PDMC interrupt handler */ diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index e97cd8f4a728..33ce5e54482b 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -503,11 +503,6 @@ unlock: return ret; } -static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { - .trigger = mchp_spdifrx_trigger, - .hw_params = mchp_spdifrx_hw_params, -}; - #define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { + .probe = mchp_spdifrx_dai_probe, + .remove = mchp_spdifrx_dai_remove, + .trigger = mchp_spdifrx_trigger, + .hw_params = mchp_spdifrx_hw_params, +}; + static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", - .probe = mchp_spdifrx_dai_probe, - .remove = mchp_spdifrx_dai_remove, .capture = { .stream_name = "S/PDIF Capture", .channels_min = SPDIFRX_CHANNELS, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index b1040576f71f..a201a96fa690 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream, SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); } -static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { - .startup = mchp_spdiftx_dai_startup, - .shutdown = mchp_spdiftx_dai_shutdown, - .trigger = mchp_spdiftx_trigger, - .hw_params = mchp_spdiftx_hw_params, - .hw_free = mchp_spdiftx_hw_free, -}; - #define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { + .probe = mchp_spdiftx_dai_probe, + .startup = mchp_spdiftx_dai_startup, + .shutdown = mchp_spdiftx_dai_shutdown, + .trigger = mchp_spdiftx_trigger, + .hw_params = mchp_spdiftx_hw_params, + .hw_free = mchp_spdiftx_hw_free, +}; + static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", - .probe = mchp_spdiftx_dai_probe, .playback = { .stream_name = "S/PDIF Playback", .channels_min = 1, -- cgit v1.2.3 From 3a8b7fd088d74c43eeb14406b7a1f0666a8d8594 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:09 +0000 Subject: ASoC: intel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871qgdb0sa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/avs/probes.c | 10 +++++++--- sound/soc/intel/catpt/pcm.c | 8 ++++++-- sound/soc/intel/keembay/kmb_platform.c | 4 +--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index ba4597bdf32e..6f986c7bbc8b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = { }; static const struct snd_soc_dai_ops sst_compr_dai_ops = { + .compress_new = snd_soc_new_compress, .mute_stream = sst_media_digital_mute, }; @@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, { .name = "compress-cpu-dai", - .compress_new = snd_soc_new_compress, .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 275928281c6c..4cab8c6c4576 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr return count; } -static const struct snd_soc_cdai_ops avs_probe_dai_ops = { +static const struct snd_soc_cdai_ops avs_probe_cdai_ops = { .startup = avs_probe_compr_open, .shutdown = avs_probe_compr_free, .set_params = avs_probe_compr_set_params, @@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = { .pointer = avs_probe_compr_pointer, }; +static const struct snd_soc_dai_ops avs_probe_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static const struct snd_compress_ops avs_probe_compress_ops = { .copy = avs_probe_compr_copy, }; @@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = { static struct snd_soc_dai_driver probe_cpu_dais[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, - .cops = &avs_probe_dai_ops, + .cops = &avs_probe_cdai_ops, + .ops = &avs_probe_dai_ops, .capture = { .stream_name = "Probe Extraction", .channels_min = 1, diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 30ca5416c9a3..f1a5cb825ff1 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, return 0; } +static const struct snd_soc_dai_ops catpt_dai_ops = { + .pcm_new = catpt_dai_pcm_new, +}; + static struct snd_soc_dai_driver dai_drivers[] = { /* FE DAIs */ { @@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = { { .name = "ssp0-port", .id = CATPT_SSP_IFACE_0, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, { .name = "ssp1-port", .id = CATPT_SSP_IFACE_1, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, }; diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index b4893365d01d..6b06b7b5ede8 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops kmb_dai_ops = { + .probe = kmb_probe, .startup = kmb_dai_startup, .trigger = kmb_dai_trigger, .hw_params = kmb_dai_hw_params, @@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; -- cgit v1.2.3 From 17821c2f6c53009b4c00aa5fd051425e19d46616 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:18 +0000 Subject: ASoC: meson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zg319m7m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-acodec-ctrl.c | 4 ++-- sound/soc/meson/aiu-codec-ctrl.c | 4 ++-- sound/soc/meson/aiu-fifo-i2s.c | 3 +++ sound/soc/meson/aiu-fifo-spdif.c | 3 +++ sound/soc/meson/aiu.c | 6 ------ sound/soc/meson/axg-frddr.c | 4 ++-- sound/soc/meson/axg-pdm.c | 18 +++++++++--------- sound/soc/meson/axg-spdifin.c | 4 ++-- sound/soc/meson/axg-tdm-interface.c | 6 ++---- sound/soc/meson/axg-toddr.c | 4 ++-- sound/soc/meson/g12a-toacodec.c | 4 ++-- sound/soc/meson/g12a-tohdmitx.c | 4 ++-- 12 files changed, 31 insertions(+), 33 deletions(-) diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index d0f0ada5f4bc..7b04b97f7b41 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = aiu_acodec_ctrl_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = { .name = "ACODEC CTRL " xname, \ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \ .ops = &aiu_acodec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_ACODEC_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 84c10956c241..ee0ef6301010 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { }; static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = { .name = "CODEC CTRL " xname, \ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \ .ops = &aiu_codec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_CODEC_CTRL_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 59e00a74b5f8..7d833500c799 100644 --- a/sound/soc/meson/aiu-fifo-i2s.c +++ b/sound/soc/meson/aiu-fifo-i2s.c @@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_i2s_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = aiu_fifo_i2s_trigger, .prepare = aiu_fifo_i2s_prepare, .hw_params = aiu_fifo_i2s_hw_params, diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index ddbd2fc40185..fa91f3c53fa4 100644 --- a/sound/soc/meson/aiu-fifo-spdif.c +++ b/sound/soc/meson/aiu-fifo-spdif.c @@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_spdif_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = fifo_spdif_trigger, .prepare = fifo_spdif_prepare, .hw_params = fifo_spdif_hw_params, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index da351a60df0c..7109b81cc3d0 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_i2s_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_i2s_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_SPDIF_FIFO] = { .name = "SPDIF FIFO", @@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_spdif_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_spdif_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_I2S_ENCODER] = { .name = "I2S Encoder", diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 61f9d417fd60..8c166a5f338c 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver axg_frddr_dai_drv = { @@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static const char * const axg_frddr_sel_texts[] = { @@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver g12a_frddr_dai_drv = { @@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index ad43cb2a1e3f..d59050914d3c 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(priv->dclk); } -static const struct snd_soc_dai_ops axg_pdm_dai_ops = { - .trigger = axg_pdm_trigger, - .hw_params = axg_pdm_hw_params, - .startup = axg_pdm_startup, - .shutdown = axg_pdm_shutdown, -}; - static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) { const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; @@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + static struct snd_soc_dai_driver axg_pdm_dai_drv = { .name = "PDM", .capture = { @@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &axg_pdm_dai_ops, - .probe = axg_pdm_dai_probe, - .remove = axg_pdm_dai_remove, }; static const struct snd_soc_component_driver axg_pdm_component_drv = { diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index e2cc4c4be758..d86880169075 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_spdifin_ops = { + .probe = axg_spdifin_dai_probe, + .remove = axg_spdifin_dai_remove, .prepare = axg_spdifin_prepare, .startup = axg_spdifin_startup, .shutdown = axg_spdifin_shutdown, @@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) drv->name = "SPDIF Input"; drv->ops = &axg_spdifin_ops; - drv->probe = axg_spdifin_dai_probe; - drv->remove = axg_spdifin_dai_remove; drv->capture.stream_name = "Capture"; drv->capture.channels_min = 1; drv->capture.channels_max = 2; diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 5e5e4c56d505..1c3d433cefd2 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_tdm_iface_ops = { + .probe = axg_tdm_iface_probe_dai, + .remove = axg_tdm_iface_remove_dai, .set_sysclk = axg_tdm_iface_set_sysclk, .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, @@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_PAD, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, [TDM_IFACE_LOOPBACK] = { .name = "TDM Loopback", @@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_LOOPBACK, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, }; diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e9208e74e965..1a0be177b8fe 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = axg_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver axg_toddr_dai_drv = { @@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const char * const axg_toddr_sel_texts[] = { @@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver g12a_toddr_dai_drv = { @@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const struct snd_soc_component_driver g12a_toddr_component_drv = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index ddc667956cf5..6c4503766fdc 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops g12a_toacodec_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = g12a_toacodec_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = { .id = (xid), \ .playback = TOACODEC_STREAM(xname, "Playback", 8), \ .ops = &g12a_toacodec_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOACODEC_OUTPUT(xname, xid) { \ diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 579a04ad4d19..f7ef9aa1eed8 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { .id = (xid), \ .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ .ops = &g12a_tohdmitx_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ -- cgit v1.2.3 From b3a7e76d7f7afd259dea954e9247dcccd361ed3a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:24 +0000 Subject: ASoC: jz4740: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y1il9m7f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 578af21769c9..517619531615 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { + .probe = jz4740_i2s_dai_probe, .startup = jz4740_i2s_startup, .shutdown = jz4740_i2s_shutdown, .trigger = jz4740_i2s_trigger, @@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver jz4740_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = { }; static struct snd_soc_dai_driver jz4770_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, -- cgit v1.2.3 From af8a0e0391308258b2338b3b72e8fad5fac2d5d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:29 +0000 Subject: ASoC: cirrus: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Alexander Sverdlin Link: https://lore.kernel.org/r/87wmy59m7a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index afc6b5b570ea..522de4b80293 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) #endif static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { + .probe = ep93xx_i2s_dai_probe, .startup = ep93xx_i2s_startup, .shutdown = ep93xx_i2s_shutdown, .hw_params = ep93xx_i2s_hw_params, @@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { static struct snd_soc_dai_driver ep93xx_i2s_dai = { .symmetric_rate = 1, - .probe = ep93xx_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 3964f1d944c9dba5444ed85a9fcdf69991f17e5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:35 +0000 Subject: ASoC: drm/vc4: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8dp9m74.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 5261526d286f..a8dec24b146b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2615,9 +2615,13 @@ static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops vc4_snd_dai_ops = { + .probe = vc4_hdmi_audio_cpu_dai_probe, +}; + static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { .name = "vc4-hdmi-cpu-dai", - .probe = vc4_hdmi_audio_cpu_dai_probe, + .ops = &vc4_snd_dai_ops, .playback = { .stream_name = "Playback", .channels_min = 1, -- cgit v1.2.3 From 69b33471a2986f655006a37b1ae7b6cccf812b53 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:41 +0000 Subject: ASoC: samsung: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt99m6y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 5 ++--- sound/soc/samsung/pcm.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f3d98abd5f0d..3af48c9b5ab7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { + .probe = samsung_i2s_dai_probe, + .remove = samsung_i2s_dai_remove, .trigger = i2s_trigger, .hw_params = i2s_hw_params, .set_fmt = i2s_set_fmt, @@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, for (i = 0; i < num_dais; i++) { dai_drv = &priv->dai_drv[i]; - dai_drv->probe = samsung_i2s_dai_probe; - dai_drv->remove = samsung_i2s_dai_remove; - dai_drv->symmetric_rate = 1; dai_drv->ops = &samsung_i2s_dai_ops; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 335fe5cb9cfc..d2cdc5c8e05b 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { - .set_sysclk = s3c_pcm_set_sysclk, - .set_clkdiv = s3c_pcm_set_clkdiv, - .trigger = s3c_pcm_trigger, - .hw_params = s3c_pcm_hw_params, - .set_fmt = s3c_pcm_set_fmt, -}; - static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) { struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai); @@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .probe = s3c_pcm_dai_probe, + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_DAI_DECLARE \ .symmetric_rate = 1, \ - .probe = s3c_pcm_dai_probe, \ .ops = &s3c_pcm_dai_ops, \ .playback = { \ .channels_min = 2, \ -- cgit v1.2.3 From df775a399e1a6eb6eeab3d23f7c200f1dd4dcce0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:52 +0000 Subject: ASoC: mediatek: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Trevor Wu Link: https://lore.kernel.org/r/87sf8t9m6n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-dai-etdm.c | 56 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index eedb9165f911..fd4f9f8f032d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_etdm_cal_mclk(afe, freq, dai->id); } -static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { - .startup = mtk_dai_etdm_startup, - .shutdown = mtk_dai_etdm_shutdown, - .hw_params = mtk_dai_etdm_hw_params, - .trigger = mtk_dai_etdm_trigger, - .set_sysclk = mtk_dai_etdm_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, - .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, -}; - -static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { - .startup = mtk_dai_hdmitx_dptx_startup, - .shutdown = mtk_dai_hdmitx_dptx_shutdown, - .hw_params = mtk_dai_hdmitx_dptx_hw_params, - .trigger = mtk_dai_hdmitx_dptx_trigger, - .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, -}; - /* dai driver */ #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000) @@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_sysclk = mtk_dai_etdm_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, + .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, +}; + static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { { .name = "DPTX", @@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_IN", @@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM1_OUT", @@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_OUT", @@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM3_OUT", @@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .rates = MTK_ETDM_RATES, .formats = MTK_ETDM_FORMATS, }, - .ops = &mtk_dai_hdmitx_dptx_ops, - .probe = mtk_dai_etdm_probe, + .ops = &mtk_dai_hdmitx_dptx_ops2, }, }; -- cgit v1.2.3 From 7575bec582876d295b34488cd39854c9e840ef04 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:58 +0000 Subject: ASoC: rockchip: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Heiko Stuebner Link: https://lore.kernel.org/r/87r0od9m6i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 2 +- sound/soc/rockchip/rockchip_i2s_tdm.c | 2 +- sound/soc/rockchip/rockchip_pdm.c | 2 +- sound/soc/rockchip/rockchip_spdif.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 575a0b9b01e9..834fbb5cf810 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { + .probe = rockchip_i2s_dai_probe, .hw_params = rockchip_i2s_hw_params, .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, .set_sysclk = rockchip_i2s_set_sysclk, @@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { }; static struct snd_soc_dai_driver rockchip_i2s_dai = { - .probe = rockchip_i2s_dai_probe, .ops = &rockchip_i2s_dai_ops, .symmetric_rate = 1, }; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 166257c6ae14..d3700f3c98e6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { + .probe = rockchip_i2s_tdm_dai_probe, .hw_params = rockchip_i2s_tdm_hw_params, .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, .set_sysclk = rockchip_i2s_tdm_set_sysclk, @@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = { }; static const struct snd_soc_dai_driver i2s_tdm_dai = { - .probe = rockchip_i2s_tdm_dai_probe, .ops = &rockchip_i2s_tdm_dai_ops, }; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 52f9aae60be8..667f2fa65c3e 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { + .probe = rockchip_pdm_dai_probe, .set_fmt = rockchip_pdm_set_fmt, .trigger = rockchip_pdm_trigger, .hw_params = rockchip_pdm_hw_params, @@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver rockchip_pdm_dai = { - .probe = rockchip_pdm_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 2, diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 0b73fe94e4bb..1a24b78e9e02 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rk_spdif_dai_ops = { + .probe = rk_spdif_dai_probe, .hw_params = rk_spdif_hw_params, .trigger = rk_spdif_trigger, }; static struct snd_soc_dai_driver rk_spdif_dai = { - .probe = rk_spdif_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 7142b49f5742d4bf5706b44db931906a45061b68 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:13 +0000 Subject: ASoC: uniphier: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3x9m62.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 161 +++++++++++++++++++++++++++++++++++------- sound/soc/uniphier/aio-ld11.c | 62 +++------------- sound/soc/uniphier/aio-pxs2.c | 55 ++------------- sound/soc/uniphier/aio.h | 10 +-- 4 files changed, 156 insertions(+), 132 deletions(-) diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 4e8d5f7532ba..7c5188477b7c 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops uniphier_aio_i2s_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .set_fmt = uniphier_aio_set_fmt, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops); - -const struct snd_soc_dai_ops uniphier_aio_spdif_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops); - -int uniphier_aio_dai_probe(struct snd_soc_dai *dai) +static int uniphier_aio_dai_probe(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); int i; @@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai) +static int uniphier_aio_dai_remove(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); @@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove); + +static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2); + +const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2); static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) { diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 7b3cf5d751f6..15dbded63804 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMIN2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .capture = { .stream_name = AUD_NAME_PCMIN2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HPCMOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 8, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops, }, { .name = AUD_NAME_EPCMOUT2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_EPCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops2, }, }; diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index 899904f7ffd6..305cb2a1253d 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_AUX, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_IECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_IECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, { .name = AUD_NAME_IECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_IECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, }; diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h index 0b03571aa9f0..09ccb47337fd 100644 --- a/sound/soc/uniphier/aio.h +++ b/sound/soc/uniphier/aio.h @@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai) int uniphier_aiodma_soc_register_platform(struct platform_device *pdev); extern const struct snd_compress_ops uniphier_aio_compress_ops; -int uniphier_aio_dai_probe(struct snd_soc_dai *dai); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai); int uniphier_aio_probe(struct platform_device *pdev); int uniphier_aio_remove(struct platform_device *pdev); -extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops; -extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2; u64 aio_rb_cnt(struct uniphier_aio_sub *sub); u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub); -- cgit v1.2.3 From 69c4f41b9e3c18bac11ada4b31abea3eed60f610 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:19 +0000 Subject: ASoC: loongson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o7jh9m5w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_i2s.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index b919f0fe8361..d45228a3a558 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { - .trigger = loongson_i2s_trigger, - .hw_params = loongson_i2s_hw_params, - .set_sysclk = loongson_i2s_set_dai_sysclk, - .set_fmt = loongson_i2s_set_fmt, -}; - static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) { struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev); @@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { + .probe = loongson_i2s_dai_probe, + .trigger = loongson_i2s_trigger, + .hw_params = loongson_i2s_hw_params, + .set_sysclk = loongson_i2s_set_dai_sysclk, + .set_fmt = loongson_i2s_set_fmt, +}; + struct snd_soc_dai_driver loongson_i2s_dai = { .name = "loongson-i2s", - .probe = loongson_i2s_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, -- cgit v1.2.3 From de046f2ddbf929a0af73dd295902ea9a55ebc741 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:25 +0000 Subject: ASoC: starfive: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Walker Chen Link: https://lore.kernel.org/r/87msz19m5r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 705f1420097b..8c117794b028 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { - .startup = jh7110_tdm_startup, - .hw_params = jh7110_tdm_hw_params, - .trigger = jh7110_tdm_trigger, - .set_fmt = jh7110_tdm_set_dai_fmt, -}; - static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) { struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); @@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { + .probe = jh7110_tdm_dai_probe, + .startup = jh7110_tdm_startup, + .hw_params = jh7110_tdm_hw_params, + .trigger = jh7110_tdm_trigger, + .set_fmt = jh7110_tdm_set_dai_fmt, +}; + #define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000 #define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = { .formats = JH7110_TDM_FORMATS, }, .ops = &jh7110_tdm_dai_ops, - .probe = jh7110_tdm_dai_probe, .symmetric_rate = 1, }; -- cgit v1.2.3 From d1f1c345562d31b1b5e2aaf03bfcdf1835778f65 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:30 +0000 Subject: ASoC: hisilicon: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leel9m5l.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 27219a9e7d0d..dd7d2a077248 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { + .probe = hi6210_i2s_dai_probe, .trigger = hi6210_i2s_trigger, .hw_params = hi6210_i2s_hw_params, .set_fmt = hi6210_i2s_set_fmt, @@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { }; static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { - .probe = hi6210_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From a350c5562318f798ef7b3e1e72bf947f0816ca45 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:36 +0000 Subject: ASoC: codecs/wm*: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu59m5f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 12 ++++++------ sound/soc/codecs/wm5102.c | 6 +++++- sound/soc/codecs/wm5110.c | 8 ++++++-- sound/soc/codecs/wm8994.c | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 36cdf97993a5..9679906c6bd5 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops wm2200_dai_ops = { - .set_fmt = wm2200_set_fmt, - .hw_params = wm2200_hw_params, -}; - static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops wm2200_dai_ops = { + .probe = wm2200_dai_probe, + .set_fmt = wm2200_set_fmt, + .hw_params = wm2200_hw_params, +}; + #define WM2200_RATES SNDRV_PCM_RATE_8000_48000 #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ @@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver wm2200_dai = { .name = "wm2200", - .probe = wm2200_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 3bdbdf3770b5..4ecf07c7448c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id, #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5102_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5102_dai[] = { { .name = "wm5102-aif1", @@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { .rates = WM5102_RATES, .formats = WM5102_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5102_dai_ops, }, { .name = "wm5102-dsp-trace", diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index ad670300de8d..ac1f2c850346 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id, #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5110_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5110_dai[] = { { .name = "wm5110-aif1", @@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-voicectrl", @@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-trace", diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bca3ebe0dac4..a48e904a9740 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = { }; static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = { + .probe = wm8994_aif2_probe, .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, @@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .formats = WM8994_FORMATS, .sig_bits = 24, }, - .probe = wm8994_aif2_probe, .ops = &wm8994_aif2_dai_ops, }, { -- cgit v1.2.3 From 7fdd0672678245dddd008fb2aea3b6952a5da795 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:42 +0000 Subject: ASoC: soc-topology: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9p9m5a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ad08d4f75a7b..e783055b6c3a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, 1 : 0; } +static const struct snd_soc_dai_ops tplg_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, } if (pcm->compress) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &tplg_dai_ops; /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); -- cgit v1.2.3 From 6bbb65c39a8468f12784bfa01d06a800c81310c5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:47 +0000 Subject: ASoC: codecs/cs47lxx: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Charles Keepax Link: https://lore.kernel.org/r/87h6p99m55.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l15.c | 6 +++++- sound/soc/codecs/cs47l24.c | 8 ++++++-- sound/soc/codecs/cs47l35.c | 8 ++++++-- sound/soc/codecs/cs47l85.c | 8 ++++++-- sound/soc/codecs/cs47l90.c | 8 ++++++-- sound/soc/codecs/cs47l92.c | 6 +++++- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index a6538dab6639..1245e1a4f2a5 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l15_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l15_dai[] = { { .name = "cs47l15-aif1", @@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l15_dai_ops, }, { .name = "cs47l15-dsp-trace", diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index a07b621d463e..cfa1d34f6ebd 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id, #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops cs47l24_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l24_dai[] = { { .name = "cs47l24-aif1", @@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-voicectrl", @@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-trace", diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index c05c80c16c84..a953f2ede1ee 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l35_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l35_dai[] = { { .name = "cs47l35-aif1", @@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-voicectrl", @@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-trace", diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index dd7997a53e70..827685481859 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l85_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l85_dai[] = { { .name = "cs47l85-aif1", @@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-voicectrl", @@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-trace", diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index cdd5e7e20b5d..2c9a5372cf51 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l90_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l90_dai[] = { { .name = "cs47l90-aif1", @@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-voicectrl", @@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-trace", diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index bc4d311d4778..352deeaff1ca 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l92_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l92_dai[] = { { .name = "cs47l92-aif1", @@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l92_dai_ops, }, { .name = "cs47l92-dsp-trace", -- cgit v1.2.3 From 707844f66ee3a79e3c1256e1b1667c9c43f6021d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:53 +0000 Subject: ASoC: codecs/cx2072x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4t9m4y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 082231088a26..f8b128084015 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops cx2072x_dai_ops2 = { + .probe = cx2072x_dsp_dai_probe, + .set_sysclk = cx2072x_set_dai_sysclk, + .set_fmt = cx2072x_set_dai_fmt, + .hw_params = cx2072x_hw_params, + .set_bclk_ratio = cx2072x_set_dai_bclk_ratio, +}; + #define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { @@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { { /* plabayck only, return echo reference to Conexant DSP chip */ .name = "cx2072x-dsp", .id = CX2072X_DAI_DSP, - .probe = cx2072x_dsp_dai_probe, .playback = { .stream_name = "DSP Playback", .channels_min = 2, @@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .rates = CX2072X_RATES_DSP, .formats = CX2072X_FORMATS, }, - .ops = &cx2072x_dai_ops, + .ops = &cx2072x_dai_ops2, }, { /* plabayck only, return echo reference through I2S TX */ .name = "cx2072x-aec", -- cgit v1.2.3 From acd3e6256edf6d81eb01ab9a6fcbc48bf038a9a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:58 +0000 Subject: ASoC: codecs/hdmi-codec: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkd9m4t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d21f69f05342..13689e718d36 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -723,24 +723,6 @@ static u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_AC97; -static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - .auto_selectable_formats = &hdmi_codec_formats, - .num_auto_selectable_formats = 1, -}; - -static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .mute_stream = hdmi_codec_mute, -}; - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ @@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .probe = hdmi_dai_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .set_fmt = hdmi_codec_i2s_set_fmt, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, +}; + +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .probe = hdmi_dai_spdif_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, +}; + static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_spdif_probe, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, -- cgit v1.2.3 From 8e1eb11cd4579decc8e928be2face7c43f2a9c67 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:59:03 +0000 Subject: ASoC: soc-dai.h: remove unused call back functions Now, all drivers are using ops call backs. Let's remove unused other call back functions. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzx9m4o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 13 ------------- sound/soc/soc-core.c | 25 ------------------------- 2 files changed, 38 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 85f897fea21a..5fcfba47d98c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -414,15 +414,6 @@ struct snd_soc_dai_driver { struct snd_soc_dobj dobj; struct of_phandle_args *dai_args; - /* DAI driver callbacks */ - int (*probe)(struct snd_soc_dai *dai); - int (*remove)(struct snd_soc_dai *dai); - /* compress dai */ - int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); - /* Optional Callback used at pcm creation*/ - int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); - /* ops */ const struct snd_soc_dai_ops *ops; const struct snd_soc_cdai_ops *cops; @@ -433,10 +424,6 @@ struct snd_soc_dai_driver { unsigned int symmetric_rate:1; unsigned int symmetric_channels:1; unsigned int symmetric_sample_bits:1; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* for Playback/Capture */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7dbf37e0ba2f..a5b96c17633a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,7 +2510,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; - struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2539,30 +2538,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; - /* REMOVE ME */ - if (dai_drv->probe || - dai_drv->remove || - dai_drv->compress_new || - dai_drv->pcm_new || - dai_drv->probe_order || - dai_drv->remove_order) { - - ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); - if (!ops) - return NULL; - if (dai_drv->ops) - memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); - - ops->probe = dai_drv->probe; - ops->remove = dai_drv->remove; - ops->compress_new = dai_drv->compress_new; - ops->pcm_new = dai_drv->pcm_new; - ops->probe_order = dai_drv->probe_order; - ops->remove_order = dai_drv->remove_order; - - dai_drv->ops = ops; - } - dai->component = component; dai->dev = dev; dai->driver = dai_drv; -- cgit v1.2.3 From 624fee45111d587ab346b2fc3bcc316615fd97e8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:50 +0000 Subject: ASoC: soc-dai.h: merge DAI call back functions into ops snd_soc_dai_driver has .ops for call back functions (A), but it also has other call back functions (B). It is duplicated and confusable. struct snd_soc_dai_driver { ... ^ int (*probe)(...); | int (*remove)(...); (B) int (*compress_new)(...); | int (*pcm_new)(...); v ... (A) const struct snd_soc_dai_ops *ops; ... } This patch merges (B) into (A). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8dpb0w6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 13 +++++++++++ sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/soc-core.c | 25 ++++++++++++++++++++ sound/soc/soc-dai.c | 44 ++++++++++++++++++++---------------- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a33d803fe548..85f897fea21a 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -274,6 +274,15 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); struct snd_soc_dai_ops { + /* DAI driver callbacks */ + int (*probe)(struct snd_soc_dai *dai); + int (*remove)(struct snd_soc_dai *dai); + /* compress dai */ + int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); + /* Optional Callback used at pcm creation*/ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); + /* * DAI clocking configuration, all optional. * Called by soc_card drivers, normally in their hw_params. @@ -355,6 +364,10 @@ struct snd_soc_dai_ops { u64 *auto_selectable_formats; int num_auto_selectable_formats; + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; + /* bit field */ unsigned int no_capture_mute:1; }; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0b8258b6bd8e..13693ef9c242 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); if (dai && (dai->component->driver->pcm_construct || - dai->driver->pcm_new)) + (dai->driver->ops && dai->driver->ops->pcm_new))) return true; return false; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a5b96c17633a..7dbf37e0ba2f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,6 +2510,7 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; + struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2538,6 +2539,30 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; + /* REMOVE ME */ + if (dai_drv->probe || + dai_drv->remove || + dai_drv->compress_new || + dai_drv->pcm_new || + dai_drv->probe_order || + dai_drv->remove_order) { + + ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); + if (!ops) + return NULL; + if (dai_drv->ops) + memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); + + ops->probe = dai_drv->probe; + ops->remove = dai_drv->remove; + ops->compress_new = dai_drv->compress_new; + ops->pcm_new = dai_drv->pcm_new; + ops->probe_order = dai_drv->probe_order; + ops->remove_order = dai_drv->remove_order; + + dai_drv->ops = ops; + } + dai->component = component; dai->dev = dev; dai->driver = dai_drv; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 73a97ac6ccb8..3f33f0630ad8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -460,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num) { int ret = -ENOTSUPP; - if (dai->driver->compress_new) - ret = dai->driver->compress_new(rtd, num); + if (dai->driver->ops && + dai->driver->ops->compress_new) + ret = dai->driver->ops->compress_new(rtd, num); return soc_dai_ret(dai, ret); } @@ -545,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->probe_order != order) - continue; - if (dai->probed) continue; - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); + if (dai->driver->ops) { + if (dai->driver->ops->probe_order != order) + continue; - if (ret < 0) - return soc_dai_ret(dai, ret); - } + if (dai->driver->ops->probe) { + int ret = dai->driver->ops->probe(dai); + if (ret < 0) + return soc_dai_ret(dai, ret); + } + } dai->probed = 1; } @@ -570,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order) int i, r, ret = 0; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->remove_order != order) + if (!dai->probed) continue; - if (dai->probed && - dai->driver->remove) { - r = dai->driver->remove(dai); - if (r < 0) - ret = r; /* use last error */ - } + if (dai->driver->ops) { + if (dai->driver->ops->remove_order != order) + continue; + if (dai->driver->ops->remove) { + r = dai->driver->ops->remove(dai); + if (r < 0) + ret = r; /* use last error */ + } + } dai->probed = 0; } @@ -592,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->pcm_new) { - int ret = dai->driver->pcm_new(rtd, dai); + if (dai->driver->ops && + dai->driver->ops->pcm_new) { + int ret = dai->driver->ops->pcm_new(rtd, dai); if (ret < 0) return soc_dai_ret(dai, ret); } -- cgit v1.2.3 From dd9d64de8ea66def69ff684a755652d6ef15d7ee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:59 +0000 Subject: ASoC: ti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt9b0vw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 22 +++++++++++----------- sound/soc/ti/davinci-mcasp.c | 27 +++++++++++++-------------- sound/soc/ti/omap-dmic.c | 22 +++++++++++----------- sound/soc/ti/omap-mcbsp.c | 28 ++++++++++++++-------------- sound/soc/ti/omap-mcpdm.c | 22 +++++++++++----------- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 97dd1634b6be..07c8b2259208 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .shutdown = davinci_i2s_shutdown, - .prepare = davinci_i2s_prepare, - .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, - .set_fmt = davinci_i2s_set_dai_fmt, - .set_clkdiv = davinci_i2s_dai_set_clkdiv, - -}; - static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .probe = davinci_i2s_dai_probe, + .shutdown = davinci_i2s_shutdown, + .prepare = davinci_i2s_prepare, + .trigger = davinci_i2s_trigger, + .hw_params = davinci_i2s_hw_params, + .set_fmt = davinci_i2s_set_dai_fmt, + .set_clkdiv = davinci_i2s_dai_set_clkdiv, + +}; + static struct snd_soc_dai_driver davinci_i2s_dai = { - .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 172fea764a31..7e7d665a5504 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, } } -static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, - .shutdown = davinci_mcasp_shutdown, - .trigger = davinci_mcasp_trigger, - .delay = davinci_mcasp_delay, - .hw_params = davinci_mcasp_hw_params, - .set_fmt = davinci_mcasp_set_dai_fmt, - .set_clkdiv = davinci_mcasp_set_clkdiv, - .set_sysclk = davinci_mcasp_set_sysclk, - .set_tdm_slot = davinci_mcasp_set_tdm_slot, -}; - static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .probe = davinci_mcasp_dai_probe, + .startup = davinci_mcasp_startup, + .shutdown = davinci_mcasp_shutdown, + .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, + .hw_params = davinci_mcasp_hw_params, + .set_fmt = davinci_mcasp_set_dai_fmt, + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, + .set_tdm_slot = davinci_mcasp_set_tdm_slot, +}; + #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "IIS Playback", .channels_min = 1, @@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "DIT Playback", .channels_min = 1, diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index cb60af36dbc3..5b5eccf303ab 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } -static const struct snd_soc_dai_ops omap_dmic_dai_ops = { - .startup = omap_dmic_dai_startup, - .shutdown = omap_dmic_dai_shutdown, - .hw_params = omap_dmic_dai_hw_params, - .prepare = omap_dmic_dai_prepare, - .trigger = omap_dmic_dai_trigger, - .set_sysclk = omap_dmic_set_dai_sysclk, -}; - static int omap_dmic_probe(struct snd_soc_dai *dai) { struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); @@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_dmic_dai_ops = { + .probe = omap_dmic_probe, + .remove = omap_dmic_remove, + .startup = omap_dmic_dai_startup, + .shutdown = omap_dmic_dai_shutdown, + .hw_params = omap_dmic_dai_hw_params, + .prepare = omap_dmic_dai_prepare, + .trigger = omap_dmic_dai_trigger, + .set_sysclk = omap_dmic_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_dmic_dai = { .name = "omap-dmic", - .probe = omap_dmic_probe, - .remove = omap_dmic_remove, .capture = { .channels_min = 2, .channels_max = 6, diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index f9fe96b61852..fdabed5133e8 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -static const struct snd_soc_dai_ops mcbsp_dai_ops = { - .startup = omap_mcbsp_dai_startup, - .shutdown = omap_mcbsp_dai_shutdown, - .prepare = omap_mcbsp_dai_prepare, - .trigger = omap_mcbsp_dai_trigger, - .delay = omap_mcbsp_dai_delay, - .hw_params = omap_mcbsp_dai_hw_params, - .set_fmt = omap_mcbsp_dai_set_dai_fmt, - .set_clkdiv = omap_mcbsp_dai_set_clkdiv, - .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, -}; - static int omap_mcbsp_probe(struct snd_soc_dai *dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); @@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mcbsp_dai_ops = { + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, + .startup = omap_mcbsp_dai_startup, + .shutdown = omap_mcbsp_dai_shutdown, + .prepare = omap_mcbsp_dai_prepare, + .trigger = omap_mcbsp_dai_trigger, + .delay = omap_mcbsp_dai_delay, + .hw_params = omap_mcbsp_dai_hw_params, + .set_fmt = omap_mcbsp_dai_set_dai_fmt, + .set_clkdiv = omap_mcbsp_dai_set_clkdiv, + .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = omap_mcbsp_probe, - .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 35deceb73427..d7d9f708f1fd 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { - .startup = omap_mcpdm_dai_startup, - .shutdown = omap_mcpdm_dai_shutdown, - .hw_params = omap_mcpdm_dai_hw_params, - .prepare = omap_mcpdm_prepare, -}; - static int omap_mcpdm_probe(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); @@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { + .probe = omap_mcpdm_probe, + .remove = omap_mcpdm_remove, + .startup = omap_mcpdm_dai_startup, + .shutdown = omap_mcpdm_dai_shutdown, + .hw_params = omap_mcpdm_dai_hw_params, + .prepare = omap_mcpdm_prepare, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, +}; + #ifdef CONFIG_PM_SLEEP static int omap_mcpdm_suspend(struct snd_soc_component *component) { @@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component) #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_probe, - .remove = omap_mcpdm_remove, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .remove_order = SND_SOC_COMP_ORDER_EARLY, .playback = { .channels_min = 1, .channels_max = 5, -- cgit v1.2.3 From b4a752b505d0819be95262cc6b2d7b3737617b82 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:06 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sf8tb0vp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index d5b6f5187f8e..7b2563075743 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axi_i2s_dai_ops = { + .probe = axi_i2s_dai_probe, .startup = axi_i2s_startup, .shutdown = axi_i2s_shutdown, .trigger = axi_i2s_trigger, @@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = { }; static struct snd_soc_dai_driver axi_i2s_dai = { - .probe = axi_i2s_dai_probe, .ops = &axi_i2s_dai_ops, .symmetric_rate = 1, }; -- cgit v1.2.3 From 7baf6b1e4f430162622838c6a13c3a2f84d5678b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:15 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0odb0vg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index e4c99bbc9cdd..10545bd99704 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops axi_spdif_dai_ops = { + .probe = axi_spdif_dai_probe, .startup = axi_spdif_startup, .shutdown = axi_spdif_shutdown, .trigger = axi_spdif_trigger, @@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = { }; static struct snd_soc_dai_driver axi_spdif_dai = { - .probe = axi_spdif_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 4062afe9861e4f45151af6a19c2f39d1894268ef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:21 +0000 Subject: ASoC: amd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3xb0va.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 24 ++++++++++++------------ sound/soc/amd/acp/acp-rembrandt.c | 3 --- sound/soc/amd/acp/acp-renoir.c | 2 -- sound/soc/amd/acp/amd.h | 1 - 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 09dc5f2c0bfc..df350014966a 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -539,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .startup = acp_i2s_startup, - .hw_params = acp_i2s_hwparams, - .prepare = acp_i2s_prepare, - .trigger = acp_i2s_trigger, - .set_fmt = acp_i2s_set_fmt, - .set_tdm_slot = acp_i2s_set_tdm_slot, -}; -EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); - -int asoc_acp_i2s_probe(struct snd_soc_dai *dai) +static int acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); @@ -569,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON); + +const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { + .probe = acp_i2s_probe, + .startup = acp_i2s_startup, + .hw_params = acp_i2s_hwparams, + .prepare = acp_i2s_prepare, + .trigger = acp_i2s_trigger, + .set_fmt = acp_i2s_set_fmt, + .set_tdm_slot = acp_i2s_set_tdm_slot, +}; +EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index cc8284f417c0..1bf7b2e68a11 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -98,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -124,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-hs", @@ -150,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 1899658ab25d..54235cad9cc9 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -97,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -123,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 2ebe2099cbb5..d6cfae6ec5f7 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -198,7 +198,6 @@ union acp_i2stdm_mstrclkgen { extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; -int asoc_acp_i2s_probe(struct snd_soc_dai *dai); int acp_platform_register(struct device *dev); int acp_platform_unregister(struct device *dev); -- cgit v1.2.3 From ddef7aff709e5b04c9c77851c6a87b0765ca363f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:27 +0000 Subject: ASoC: dwc: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Maxim Kochetkov Link: https://lore.kernel.org/r/87o7jhb0v4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 1f1ee14b04e6..0a4698008d64 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -443,7 +443,16 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask return 0; } +static int dw_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); + return 0; +} + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .probe = dw_i2s_dai_probe, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, @@ -680,14 +689,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } -static int dw_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); - return 0; -} - static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; @@ -706,7 +707,6 @@ static int dw_i2s_probe(struct platform_device *pdev) return -ENOMEM; dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->probe = dw_i2s_dai_probe; dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->i2s_base)) -- cgit v1.2.3 From 598d2dce58ffae5ca090a4cf36b7543e7069a16a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:41 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87msz1b0uq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index a1ed141b8795..abfaf3cdf5bb 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { + .probe = mmp_sspa_probe, .startup = mmp_sspa_startup, .shutdown = mmp_sspa_shutdown, .trigger = mmp_sspa_trigger, @@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { }; static struct snd_soc_dai_driver mmp_sspa_dai = { - .probe = mmp_sspa_probe, .playback = { .channels_min = 1, .channels_max = 128, -- cgit v1.2.3 From 755ecb00620b1dda0b3dade626ea711aad16bfa7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:47 +0000 Subject: ASoC: bcm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leelb0uk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 85f705afcdbb..9bda6499e66e 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream, bcm2835_i2s_stop_clock(dev); } +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, + &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], + &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); + + return 0; +} + static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { + .probe = bcm2835_i2s_dai_probe, .startup = bcm2835_i2s_startup, .shutdown = bcm2835_i2s_shutdown, .prepare = bcm2835_i2s_prepare, @@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, }; -static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, - &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return 0; -} - static struct snd_soc_dai_driver bcm2835_i2s_dai = { .name = "bcm2835-i2s", - .probe = bcm2835_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From ac27ca16a0bbbac2d38211634c15827d37a5150e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:53 +0000 Subject: ASoC: fsl: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu5b0ue.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_aud2htx.c | 10 +++++----- sound/soc/fsl/fsl_easrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_esai.c | 20 ++++++++++---------- sound/soc/fsl/fsl_micfil.c | 14 +++++++------- sound/soc/fsl/fsl_sai.c | 24 ++++++++++++------------ sound/soc/fsl/fsl_spdif.c | 17 ++++++++--------- sound/soc/fsl/fsl_ssi.c | 3 +-- sound/soc/fsl/fsl_xcvr.c | 16 ++++++++-------- 9 files changed, 67 insertions(+), 69 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index adb8a59de2bd..b793263291dc 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { - .startup = fsl_asrc_dai_startup, - .hw_params = fsl_asrc_dai_hw_params, - .hw_free = fsl_asrc_dai_hw_free, - .trigger = fsl_asrc_dai_trigger, -}; - static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) { struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); @@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .probe = fsl_asrc_dai_probe, + .startup = fsl_asrc_dai_startup, + .hw_params = fsl_asrc_dai_hw_params, + .hw_free = fsl_asrc_dai_hw_free, + .trigger = fsl_asrc_dai_trigger, +}; + #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_3LE) static struct snd_soc_dai_driver fsl_asrc_dai = { - .probe = fsl_asrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 46b0c5dcc4a5..fc56f6ade368 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { - .trigger = fsl_aud2htx_trigger, -}; - static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev); @@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { + .probe = fsl_aud2htx_dai_probe, + .trigger = fsl_aud2htx_trigger, +}; + static struct snd_soc_dai_driver fsl_aud2htx_dai = { - .probe = fsl_aud2htx_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 670cbdb361b6..ba62995c909a 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { - .startup = fsl_easrc_startup, - .trigger = fsl_easrc_trigger, - .hw_params = fsl_easrc_hw_params, - .hw_free = fsl_easrc_hw_free, -}; - static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); @@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { + .probe = fsl_easrc_dai_probe, + .startup = fsl_easrc_startup, + .trigger = fsl_easrc_trigger, + .hw_params = fsl_easrc_hw_params, + .hw_free = fsl_easrc_hw_free, +}; + static struct snd_soc_dai_driver fsl_easrc_dai = { - .probe = fsl_easrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 936f0cd4b06d..d0d8a01da9bd 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_esai_dai_ops = { - .startup = fsl_esai_startup, - .trigger = fsl_esai_trigger, - .hw_params = fsl_esai_hw_params, - .set_sysclk = fsl_esai_set_dai_sysclk, - .set_fmt = fsl_esai_set_dai_fmt, - .set_tdm_slot = fsl_esai_set_dai_tdm_slot, -}; - static int fsl_esai_dai_probe(struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); @@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_esai_dai_ops = { + .probe = fsl_esai_dai_probe, + .startup = fsl_esai_startup, + .trigger = fsl_esai_trigger, + .hw_params = fsl_esai_hw_params, + .set_sysclk = fsl_esai_set_dai_sysclk, + .set_fmt = fsl_esai_set_dai_fmt, + .set_tdm_slot = fsl_esai_set_dai_tdm_slot, +}; + static struct snd_soc_dai_driver fsl_esai_dai = { - .probe = fsl_esai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index bbaad6ec2e72..0d37edb70261 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -764,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { - .startup = fsl_micfil_startup, - .trigger = fsl_micfil_trigger, - .hw_params = fsl_micfil_hw_params, -}; - static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -807,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .probe = fsl_micfil_dai_probe, + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, +}; + static struct snd_soc_dai_driver fsl_micfil_dai = { - .probe = fsl_micfil_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index f7676d30c82f..1e4020fae05a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { - .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, - .set_sysclk = fsl_sai_set_dai_sysclk, - .set_fmt = fsl_sai_set_dai_fmt, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, - .hw_params = fsl_sai_hw_params, - .hw_free = fsl_sai_hw_free, - .trigger = fsl_sai_trigger, - .startup = fsl_sai_startup, -}; - static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); @@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { + .probe = fsl_sai_dai_probe, + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, + .set_sysclk = fsl_sai_set_dai_sysclk, + .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .hw_params = fsl_sai_hw_params, + .hw_free = fsl_sai_hw_free, + .trigger = fsl_sai_trigger, + .startup = fsl_sai_startup, +}; + static int fsl_sai_dai_resume(struct snd_soc_component *component) { struct fsl_sai *sai = snd_soc_component_get_drvdata(component); @@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) } static struct snd_soc_dai_driver fsl_sai_dai_template = { - .probe = fsl_sai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 95bb8b10494a..78d9dfbe6548 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -765,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { - .startup = fsl_spdif_startup, - .hw_params = fsl_spdif_hw_params, - .trigger = fsl_spdif_trigger, - .shutdown = fsl_spdif_shutdown, -}; - - /* * FSL SPDIF IEC958 controller(mixer) functions * @@ -1283,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { + .probe = fsl_spdif_dai_probe, + .startup = fsl_spdif_startup, + .hw_params = fsl_spdif_hw_params, + .trigger = fsl_spdif_trigger, + .shutdown = fsl_spdif_shutdown, +}; + static struct snd_soc_dai_driver fsl_spdif_dai = { - .probe = &fsl_spdif_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 53ed3701b0b0..079ac04272b8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { + .probe = fsl_ssi_dai_probe, .startup = fsl_ssi_startup, .shutdown = fsl_ssi_shutdown, .hw_params = fsl_ssi_hw_params, @@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { }; static struct snd_soc_dai_driver fsl_ssi_dai_template = { - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, @@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .symmetric_channels = 1, - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU AC97 Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 318fe77683f5..fa0a15263c66 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { }, }; -static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { - .prepare = fsl_xcvr_prepare, - .startup = fsl_xcvr_startup, - .shutdown = fsl_xcvr_shutdown, - .trigger = fsl_xcvr_trigger, -}; - static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); @@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { + .probe = fsl_xcvr_dai_probe, + .prepare = fsl_xcvr_prepare, + .startup = fsl_xcvr_startup, + .shutdown = fsl_xcvr_shutdown, + .trigger = fsl_xcvr_trigger, +}; + static struct snd_soc_dai_driver fsl_xcvr_dai = { - .probe = fsl_xcvr_dai_probe, .ops = &fsl_xcvr_dai_ops, .playback = { .stream_name = "CPU-Playback", -- cgit v1.2.3 From ca6b2aac2ad49101d058f8f1d5099d36fd7b5360 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:59 +0000 Subject: ASoC: img: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9pb0u8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/img/img-i2s-in.c | 14 +++++++------- sound/soc/img/img-i2s-out.c | 14 +++++++------- sound/soc/img/img-parallel-out.c | 14 +++++++------- sound/soc/img/img-spdif-in.c | 12 ++++++------ sound/soc/img/img-spdif-out.c | 12 ++++++------ 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index b7ab8467b5cf..b6b6339c164b 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { - .trigger = img_i2s_in_trigger, - .hw_params = img_i2s_in_hw_params, - .set_fmt = img_i2s_in_set_fmt -}; - static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); @@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .probe = img_i2s_in_dai_probe, + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_in_component = { .name = "img-i2s-in", .legacy_dai_naming = 1, @@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; i2s->dma_data.addr_width = 4; - i2s->dai_driver.probe = img_i2s_in_dai_probe; i2s->dai_driver.capture.channels_min = 2; i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index fe95ddfb8407..41ea5ba52181 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { - .trigger = img_i2s_out_trigger, - .hw_params = img_i2s_out_hw_params, - .set_fmt = img_i2s_out_set_fmt -}; - static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); @@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .probe = img_i2s_out_dai_probe, + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_out_component = { .name = "img-i2s-out", .legacy_dai_naming = 1, @@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->dma_data.addr_width = 4; i2s->dma_data.maxburst = 4; - i2s->dai_driver.probe = img_i2s_out_dai_probe; i2s->dai_driver.playback.channels_min = 2; i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index df1291ee2b3b..815e68a7048c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_prl_out_dai_ops = { - .trigger = img_prl_out_trigger, - .hw_params = img_prl_out_hw_params, - .set_fmt = img_prl_out_set_fmt -}; - static int img_prl_out_dai_probe(struct snd_soc_dai *dai) { struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); @@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .probe = img_prl_out_dai_probe, + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + static struct snd_soc_dai_driver img_prl_out_dai = { - .probe = img_prl_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 558062a1804a..9646e9d3f0bc 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, return img_spdif_in_do_clkgen_single(spdif, rate); } -static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { - .trigger = img_spdif_in_trigger, - .hw_params = img_spdif_in_hw_params -}; - static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); @@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .probe = img_spdif_in_dai_probe, + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + static struct snd_soc_dai_driver img_spdif_in_dai = { - .probe = img_spdif_in_dai_probe, .capture = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index b13e128e50d6..dfa72afa946e 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { - .trigger = img_spdif_out_trigger, - .hw_params = img_spdif_out_hw_params -}; - static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); @@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .probe = img_spdif_out_dai_probe, + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + static struct snd_soc_dai_driver img_spdif_out_dai = { - .probe = img_spdif_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 450e7222236370e79fd3b75105967dc1e5cc0919 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:05 +0000 Subject: ASoC: sof: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6p9b0u2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 5530b5d793d0..740b637822db 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = { .owner = THIS_MODULE, }; +static const struct snd_soc_dai_ops sof_probes_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver sof_probes_dai_drv[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, + .ops = &sof_probes_dai_ops, .cops = &sof_probes_compr_ops, .capture = { .stream_name = "Probe Extraction", -- cgit v1.2.3 From 9f625f5e6cf9248796faaf1fb9368147dce82ca9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:11 +0000 Subject: ASoC: sti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4tb0tw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index a4d74d1e3c24..2c21a86421e6 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) return sti_uniperiph_dai_create_ctrl(dai); } -static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { +static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = { .probe = sti_uniperiph_dai_probe, }; +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .ops = &sti_uniperiph_dai_ops, +}; + static const struct snd_soc_component_driver sti_uniperiph_dai_component = { .name = "sti_cpu_dai", .suspend = sti_uniperiph_suspend, -- cgit v1.2.3 From 53c577ba4f506afe450733d583c529cd7214563b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:17 +0000 Subject: ASoC: stm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkdb0tq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 2 +- sound/soc/stm/stm32_sai_sub.c | 18 ++++++++++++++---- sound/soc/stm/stm32_spdifrx.c | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 387130701960..06a42130f5e4 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { }; static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { + .probe = stm32_i2s_dai_probe, .set_sysclk = stm32_i2s_set_sysclk, .set_fmt = stm32_i2s_set_dai_fmt, .startup = stm32_i2s_startup, @@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; - dai_ptr->probe = stm32_i2s_dai_probe; dai_ptr->ops = &stm32_i2s_pcm_dai_ops; dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 271ec5b3378d..42d67b7a68e8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) } static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { + .probe = stm32_sai_dai_probe, + .set_sysclk = stm32_sai_set_sysclk, + .set_fmt = stm32_sai_set_dai_fmt, + .set_tdm_slot = stm32_sai_set_dai_tdm_slot, + .startup = stm32_sai_startup, + .hw_params = stm32_sai_hw_params, + .trigger = stm32_sai_trigger, + .shutdown = stm32_sai_shutdown, + .pcm_new = stm32_sai_pcm_new, +}; + +static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = { + .probe = stm32_sai_dai_probe, .set_sysclk = stm32_sai_set_sysclk, .set_fmt = stm32_sai_set_dai_fmt, .set_tdm_slot = stm32_sai_set_dai_tdm_slot, @@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = { }; static struct snd_soc_dai_driver stm32_sai_playback_dai = { - .probe = stm32_sai_dai_probe, - .pcm_new = stm32_sai_pcm_new, .id = 1, /* avoid call to fmt_single_name() */ .playback = { .channels_min = 1, @@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { }; static struct snd_soc_dai_driver stm32_sai_capture_dai = { - .probe = stm32_sai_dai_probe, .id = 1, /* avoid call to fmt_single_name() */ .capture = { .channels_min = 1, @@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &stm32_sai_pcm_dai_ops, + .ops = &stm32_sai_pcm_dai_ops2, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index a4066f271f2d..a359b528b26b 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { + .probe = stm32_spdifrx_dai_probe, .startup = stm32_spdifrx_startup, .hw_params = stm32_spdifrx_hw_params, .trigger = stm32_spdifrx_trigger, @@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { { - .probe = stm32_spdifrx_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, -- cgit v1.2.3 From e41906778603cd4534fded6d9fa5302918c1c169 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:22 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzxb0tl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d19769dde139..b70034c07eee 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -813,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, .startup = pxa_ssp_startup, .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, @@ -824,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { }; static struct snd_soc_dai_driver pxa_ssp_dai = { - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, .playback = { .channels_min = 1, .channels_max = 8, -- cgit v1.2.3 From 4b0891a7b60a6fd8a047a0e74a4c37d62d43402a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:28 +0000 Subject: ASoC: rsnd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkfhb0tg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cf2031b7e209..e29c2fee9521 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) @@ -1355,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, return 0; } -static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); int ret; @@ -1382,6 +1370,18 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .pcm_new = rsnd_soc_dai_pcm_new, + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, + .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), +}; + static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, struct device_node *node_np, @@ -1411,7 +1411,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; - drv->pcm_new = rsnd_pcm_new; drv->id = dai_i; drv->dai_args = &rdai->dai_args; -- cgit v1.2.3 From e4222bbdecf4a5d5c25df753e9f5aefd96368ae3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:34 +0000 Subject: ASoC: qcom: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a5v1b0ta.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 4 -- sound/soc/qcom/lpass-cpu.c | 40 +++++++++------ sound/soc/qcom/lpass-ipq806x.c | 1 - sound/soc/qcom/lpass-sc7180.c | 5 +- sound/soc/qcom/lpass-sc7280.c | 2 - sound/soc/qcom/lpass.h | 4 +- sound/soc/qcom/qdsp6/q6afe-dai.c | 88 +++++++++++++++++--------------- sound/soc/qcom/qdsp6/q6asm-dai.c | 6 ++- sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c | 3 -- 9 files changed, 80 insertions(+), 73 deletions(-) diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index abaf694ee9a3..f919d46e18ca 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_SECONDARY] = { @@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_TERTIARY] = { @@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_QUATERNARY] = { @@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, }; diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index dbdaaa85ce48..39571fed4001 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { - .set_sysclk = lpass_cpu_daiops_set_sysclk, - .startup = lpass_cpu_daiops_startup, - .shutdown = lpass_cpu_daiops_shutdown, - .hw_params = lpass_cpu_daiops_hw_params, - .trigger = lpass_cpu_daiops_trigger, - .prepare = lpass_cpu_daiops_prepare, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); - -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { int ret; struct snd_soc_dai_driver *drv = dai->driver; @@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } -EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) +static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; @@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) return ret; } -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = { + .pcm_new = lpass_cpu_daiops_pcm_new, + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2); static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index ef8a7984f232..2c97f295e394 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 56db852f4eab..d16c0d83aaad 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, - .ops = &asoc_qcom_lpass_cpu_dai_ops, - .pcm_new = lpass_cpu_pcm_new, + .ops = &asoc_qcom_lpass_cpu_dai_ops2, }, { .id = LPASS_DP_RX, .name = "Hdmi", diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index bcf18fe8e14d..6b2eb25ed939 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = LPASS_DP_RX, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index dd78600fc7b0..bdfe66ec3314 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2; extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops; #endif /* __LPASS_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index dbff55a97162..3faa7e0eb0dd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, }; -static const struct snd_soc_dai_ops q6hdmi_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6hdmi_hw_params, - .shutdown = q6afe_dai_shutdown, -}; - -static const struct snd_soc_dai_ops q6i2s_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6i2s_hw_params, - .set_fmt = q6i2s_set_fmt, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, -}; - -static const struct snd_soc_dai_ops q6slim_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6slim_hw_params, - .shutdown = q6afe_dai_shutdown, - .set_channel_map = q6slim_set_channel_map, -}; - -static const struct snd_soc_dai_ops q6tdm_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_tdm_slot = q6tdm_set_tdm_slot, - .set_channel_map = q6tdm_set_channel_map, - .hw_params = q6tdm_hw_params, -}; - -static const struct snd_soc_dai_ops q6dma_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_channel_map = q6dma_set_channel_map, - .hw_params = q6dma_hw_params, -}; - static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops q6hdmi_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static const struct snd_soc_dai_ops q6i2s_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static const struct snd_soc_dai_ops q6slim_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static const struct snd_soc_dai_ops q6tdm_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_tdm_slot = q6tdm_set_tdm_slot, + .set_channel_map = q6tdm_set_channel_map, + .hw_params = q6tdm_hw_params, +}; + +static const struct snd_soc_dai_ops q6dma_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, +}; + static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev) dev_set_drvdata(dev, dai_data); of_q6afe_parse_dai_data(dev, dai_data); - cfg.probe = msm_dai_q6_dai_probe; - cfg.remove = msm_dai_q6_dai_remove; cfg.q6hdmi_ops = &q6hdmi_ops; cfg.q6slim_ops = &q6slim_ops; cfg.q6i2s_ops = &q6i2s_ops; diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 5fc8088e63c8..fe0666e9fd23 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = { Q6ASM_FEDAI_DRIVER(8), }; +static const struct snd_soc_dai_ops q6asm_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int of_q6asm_parse_dai_data(struct device *dev, struct q6asm_dai_data *pdata) { @@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev, dai_drv->playback = empty_stream; if (of_property_read_bool(node, "is-compress-dai")) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &q6asm_dai_ops; } return 0; diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index ac937a6bf909..4919001de08b 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, int i; for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) { - q6dsp_audio_fe_dais[i].probe = cfg->probe; - q6dsp_audio_fe_dais[i].remove = cfg->remove; - switch (q6dsp_audio_fe_dais[i].id) { case HDMI_RX: case DISPLAY_PORT_RX: -- cgit v1.2.3 From 2d2f3044440eee6a90d1dc4e05388e03be6f4b0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:41 +0000 Subject: ASoC: au1x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ralb0t3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/ac97c.c | 10 +++++----- sound/soc/au1x/psc-ac97.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index a11d6841afc2..b0e1a1253e10 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops alchemy_ac97c_ops = { - .startup = alchemy_ac97c_startup, -}; - static int au1xac97c_dai_probe(struct snd_soc_dai *dai) { return ac97c_workdata ? 0 : -ENODEV; } +static const struct snd_soc_dai_ops alchemy_ac97c_ops = { + .probe = au1xac97c_dai_probe, + .startup = alchemy_ac97c_startup, +}; + static struct snd_soc_dai_driver au1xac97c_dai_driver = { .name = "alchemy-ac97c", - .probe = au1xac97c_dai_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 9fd91aea7d1a..5d50ebc2bdd5 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .probe = au1xpsc_ac97_probe, .startup = au1xpsc_ac97_startup, .trigger = au1xpsc_ac97_trigger, .hw_params = au1xpsc_ac97_hw_params, }; static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { - .probe = au1xpsc_ac97_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, -- cgit v1.2.3 From ce11656ccdc9cb520d8beb07854dec1875017282 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:46 +0000 Subject: ASoC: ux500: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Linus Walleij Link: https://lore.kernel.org/r/877cq5b0sx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 44e88dad8584..cde0dd8e2569 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { { + .probe = ux500_msp_dai_of_probe, .set_sysclk = ux500_msp_dai_set_dai_sysclk, .set_fmt = ux500_msp_dai_set_dai_fmt, .set_tdm_slot = ux500_msp_dai_set_tdm_slot, @@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { }; static struct snd_soc_dai_driver ux500_msp_dai_drv = { - .probe = ux500_msp_dai_of_probe, .playback.channels_min = UX500_MSP_MIN_CHANNELS, .playback.channels_max = UX500_MSP_MAX_CHANNELS, .playback.rates = UX500_I2S_RATES, -- cgit v1.2.3 From fc95a8a3eaebff8130bd34a43e6a0fc14aa766d9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:52 +0000 Subject: ASoC: sunxi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/875y5pb0sr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 6 +++++- sound/soc/sunxi/sun4i-i2s.c | 18 +++++++++--------- sound/soc/sunxi/sun4i-spdif.c | 2 +- sound/soc/sunxi/sun50i-dmic.c | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 55328850aef5..f0a5fd901101 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops dummy_dai_ops = { + .probe = sun4i_codec_dai_probe, +}; + static struct snd_soc_dai_driver dummy_cpu_dai = { .name = "sun4i-codec-cpu-dai", - .probe = sun4i_codec_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .ops = &dummy_dai_ops, }; static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 669d712bbe9f..5124b6c9ceb4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, return 0; } -static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { - .hw_params = sun4i_i2s_hw_params, - .set_fmt = sun4i_i2s_set_fmt, - .set_sysclk = sun4i_i2s_set_sysclk, - .set_tdm_slot = sun4i_i2s_set_tdm_slot, - .trigger = sun4i_i2s_trigger, -}; - static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { + .probe = sun4i_i2s_dai_probe, + .hw_params = sun4i_i2s_hw_params, + .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, + .trigger = sun4i_i2s_trigger, +}; + #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver sun4i_i2s_dai = { - .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index c2b55d2e5fe1..b849bb7cf58e 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = { + .probe = sun4i_spdif_soc_dai_probe, .startup = sun4i_spdif_startup, .trigger = sun4i_spdif_trigger, .hw_params = sun4i_spdif_hw_params, @@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { .rates = SUN4I_RATES, .formats = SUN4I_FORMATS, }, - .probe = sun4i_spdif_soc_dai_probe, .ops = &sun4i_spdif_dai_ops, .name = "spdif", }; diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index c10439b9e0a2..2599683a582d 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = { + .probe = sun50i_dmic_soc_dai_probe, .startup = sun50i_dmic_startup, .trigger = sun50i_dmic_trigger, .hw_params = sun50i_dmic_hw_params, @@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = { .formats = SUN50I_DMIC_FORMATS, .sig_bits = 21, }, - .probe = sun50i_dmic_soc_dai_probe, .ops = &sun50i_dmic_dai_ops, .name = "dmic", }; -- cgit v1.2.3 From 516ee7009ff20eb3f73a64a1fe2ffe10997696e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:58 +0000 Subject: ASoC: tegra: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874jl9b0sl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 10 +++++----- sound/soc/tegra/tegra20_i2s.c | 2 +- sound/soc/tegra/tegra20_spdif.c | 2 +- sound/soc/tegra/tegra210_admaif.c | 12 ++++++------ sound/soc/tegra/tegra30_i2s.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 60e7df41c64c..e713feca25fa 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { - .trigger = tegra20_ac97_trigger, -}; - static int tegra20_ac97_probe(struct snd_soc_dai *dai) { struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); @@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { + .probe = tegra20_ac97_probe, + .trigger = tegra20_ac97_trigger, +}; + static struct snd_soc_dai_driver tegra20_ac97_dai = { .name = "tegra-ac97-pcm", - .probe = tegra20_ac97_probe, .playback = { .stream_name = "PCM Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index d38b58305c6b..f11618e8f13e 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { + .probe = tegra20_i2s_probe, .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, .trigger = tegra20_i2s_trigger, @@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { - .probe = tegra20_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index d034803695a0..b0670aa4d967 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { + .probe = tegra20_spdif_probe, .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, .startup = tegra20_spdif_startup, @@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { static struct snd_soc_dai_driver tegra20_spdif_dai = { .name = "tegra20-spdif", - .probe = tegra20_spdif_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 6868508585a0..9f9334e48049 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, } } -static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { - .hw_params = tegra_admaif_hw_params, - .trigger = tegra_admaif_trigger, -}; - static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { + .probe = tegra_admaif_dai_probe, + .hw_params = tegra_admaif_hw_params, + .trigger = tegra_admaif_trigger, +}; + #define DAI(dai_name) \ { \ .name = dai_name, \ - .probe = tegra_admaif_dai_probe, \ .playback = { \ .stream_name = dai_name " Playback", \ .channels_min = 1, \ diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 644280603095..81eaece51130 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { + .probe = tegra30_i2s_probe, .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, @@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { - .probe = tegra30_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 2ff8a43d4d4eec1f74cc024b21fe6737faaa69f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:04 +0000 Subject: ASoC: atmel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87350tb0sg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 16 ++++++++-------- sound/soc/atmel/mchp-i2s-mcc.c | 24 ++++++++++++------------ sound/soc/atmel/mchp-pdmc.c | 18 +++++++++--------- sound/soc/atmel/mchp-spdifrx.c | 14 +++++++------- sound/soc/atmel/mchp-spdiftx.c | 18 +++++++++--------- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 4febd4d3d0fa..6c20c643f321 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return err; } -static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { - .prepare = atmel_i2s_prepare, - .trigger = atmel_i2s_trigger, - .hw_params = atmel_i2s_hw_params, - .set_fmt = atmel_i2s_set_dai_fmt, -}; - static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) { struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { + .probe = atmel_i2s_dai_probe, + .prepare = atmel_i2s_prepare, + .trigger = atmel_i2s_trigger, + .hw_params = atmel_i2s_hw_params, + .set_fmt = atmel_i2s_set_dai_fmt, +}; + static struct snd_soc_dai_driver atmel_i2s_dai = { - .probe = atmel_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 4b8a63295f89..25ed0b953bfd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .set_sysclk = mchp_i2s_mcc_set_sysclk, - .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, - .startup = mchp_i2s_mcc_startup, - .trigger = mchp_i2s_mcc_trigger, - .hw_params = mchp_i2s_mcc_hw_params, - .hw_free = mchp_i2s_mcc_hw_free, - .set_fmt = mchp_i2s_mcc_set_dai_fmt, - .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, -}; - static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) { struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { + .probe = mchp_i2s_mcc_dai_probe, + .set_sysclk = mchp_i2s_mcc_set_sysclk, + .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, + .startup = mchp_i2s_mcc_startup, + .trigger = mchp_i2s_mcc_trigger, + .hw_params = mchp_i2s_mcc_hw_params, + .hw_free = mchp_i2s_mcc_hw_free, + .set_fmt = mchp_i2s_mcc_set_dai_fmt, + .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, +}; + #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { - .probe = mchp_i2s_mcc_dai_probe, .playback = { .stream_name = "I2SMCC-Playback", .channels_min = 1, diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index c79c73e6791e..944d78ef2f36 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -706,13 +706,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .set_fmt = mchp_pdmc_set_fmt, - .startup = mchp_pdmc_startup, - .hw_params = mchp_pdmc_hw_params, - .trigger = mchp_pdmc_trigger, -}; - static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd) { struct mchp_pdmc_chmap *info; @@ -765,8 +758,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, return ret; } +static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { + .probe = mchp_pdmc_dai_probe, + .set_fmt = mchp_pdmc_set_fmt, + .startup = mchp_pdmc_startup, + .hw_params = mchp_pdmc_hw_params, + .trigger = mchp_pdmc_trigger, + .pcm_new = &mchp_pdmc_pcm_new, +}; + static struct snd_soc_dai_driver mchp_pdmc_dai = { - .probe = mchp_pdmc_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -777,7 +778,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, .ops = &mchp_pdmc_dai_ops, - .pcm_new = &mchp_pdmc_pcm_new, }; /* PDMC interrupt handler */ diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index e97cd8f4a728..33ce5e54482b 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -503,11 +503,6 @@ unlock: return ret; } -static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { - .trigger = mchp_spdifrx_trigger, - .hw_params = mchp_spdifrx_hw_params, -}; - #define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { + .probe = mchp_spdifrx_dai_probe, + .remove = mchp_spdifrx_dai_remove, + .trigger = mchp_spdifrx_trigger, + .hw_params = mchp_spdifrx_hw_params, +}; + static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", - .probe = mchp_spdifrx_dai_probe, - .remove = mchp_spdifrx_dai_remove, .capture = { .stream_name = "S/PDIF Capture", .channels_min = SPDIFRX_CHANNELS, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index b1040576f71f..a201a96fa690 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream, SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); } -static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { - .startup = mchp_spdiftx_dai_startup, - .shutdown = mchp_spdiftx_dai_shutdown, - .trigger = mchp_spdiftx_trigger, - .hw_params = mchp_spdiftx_hw_params, - .hw_free = mchp_spdiftx_hw_free, -}; - #define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { + .probe = mchp_spdiftx_dai_probe, + .startup = mchp_spdiftx_dai_startup, + .shutdown = mchp_spdiftx_dai_shutdown, + .trigger = mchp_spdiftx_trigger, + .hw_params = mchp_spdiftx_hw_params, + .hw_free = mchp_spdiftx_hw_free, +}; + static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", - .probe = mchp_spdiftx_dai_probe, .playback = { .stream_name = "S/PDIF Playback", .channels_min = 1, -- cgit v1.2.3 From e9f512121e6ae491aac255849eabeb3d2b1e4199 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:09 +0000 Subject: ASoC: intel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871qgdb0sa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/avs/probes.c | 10 +++++++--- sound/soc/intel/catpt/pcm.c | 8 ++++++-- sound/soc/intel/keembay/kmb_platform.c | 4 +--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index ba4597bdf32e..6f986c7bbc8b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = { }; static const struct snd_soc_dai_ops sst_compr_dai_ops = { + .compress_new = snd_soc_new_compress, .mute_stream = sst_media_digital_mute, }; @@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, { .name = "compress-cpu-dai", - .compress_new = snd_soc_new_compress, .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 275928281c6c..4cab8c6c4576 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr return count; } -static const struct snd_soc_cdai_ops avs_probe_dai_ops = { +static const struct snd_soc_cdai_ops avs_probe_cdai_ops = { .startup = avs_probe_compr_open, .shutdown = avs_probe_compr_free, .set_params = avs_probe_compr_set_params, @@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = { .pointer = avs_probe_compr_pointer, }; +static const struct snd_soc_dai_ops avs_probe_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static const struct snd_compress_ops avs_probe_compress_ops = { .copy = avs_probe_compr_copy, }; @@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = { static struct snd_soc_dai_driver probe_cpu_dais[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, - .cops = &avs_probe_dai_ops, + .cops = &avs_probe_cdai_ops, + .ops = &avs_probe_dai_ops, .capture = { .stream_name = "Probe Extraction", .channels_min = 1, diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 30ca5416c9a3..f1a5cb825ff1 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, return 0; } +static const struct snd_soc_dai_ops catpt_dai_ops = { + .pcm_new = catpt_dai_pcm_new, +}; + static struct snd_soc_dai_driver dai_drivers[] = { /* FE DAIs */ { @@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = { { .name = "ssp0-port", .id = CATPT_SSP_IFACE_0, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, { .name = "ssp1-port", .id = CATPT_SSP_IFACE_1, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, }; diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index b4893365d01d..6b06b7b5ede8 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops kmb_dai_ops = { + .probe = kmb_probe, .startup = kmb_dai_startup, .trigger = kmb_dai_trigger, .hw_params = kmb_dai_hw_params, @@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; -- cgit v1.2.3 From 2d3155a90757ec37f50c0aa98a532e5d0a61b953 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:18 +0000 Subject: ASoC: meson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zg319m7m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-acodec-ctrl.c | 4 ++-- sound/soc/meson/aiu-codec-ctrl.c | 4 ++-- sound/soc/meson/aiu-fifo-i2s.c | 3 +++ sound/soc/meson/aiu-fifo-spdif.c | 3 +++ sound/soc/meson/aiu.c | 6 ------ sound/soc/meson/axg-frddr.c | 4 ++-- sound/soc/meson/axg-pdm.c | 18 +++++++++--------- sound/soc/meson/axg-spdifin.c | 4 ++-- sound/soc/meson/axg-tdm-interface.c | 6 ++---- sound/soc/meson/axg-toddr.c | 4 ++-- sound/soc/meson/g12a-toacodec.c | 4 ++-- sound/soc/meson/g12a-tohdmitx.c | 4 ++-- 12 files changed, 31 insertions(+), 33 deletions(-) diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index d0f0ada5f4bc..7b04b97f7b41 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = aiu_acodec_ctrl_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = { .name = "ACODEC CTRL " xname, \ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \ .ops = &aiu_acodec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_ACODEC_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 84c10956c241..ee0ef6301010 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { }; static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = { .name = "CODEC CTRL " xname, \ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \ .ops = &aiu_codec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_CODEC_CTRL_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 59e00a74b5f8..7d833500c799 100644 --- a/sound/soc/meson/aiu-fifo-i2s.c +++ b/sound/soc/meson/aiu-fifo-i2s.c @@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_i2s_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = aiu_fifo_i2s_trigger, .prepare = aiu_fifo_i2s_prepare, .hw_params = aiu_fifo_i2s_hw_params, diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index ddbd2fc40185..fa91f3c53fa4 100644 --- a/sound/soc/meson/aiu-fifo-spdif.c +++ b/sound/soc/meson/aiu-fifo-spdif.c @@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_spdif_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = fifo_spdif_trigger, .prepare = fifo_spdif_prepare, .hw_params = fifo_spdif_hw_params, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index da351a60df0c..7109b81cc3d0 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_i2s_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_i2s_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_SPDIF_FIFO] = { .name = "SPDIF FIFO", @@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_spdif_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_spdif_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_I2S_ENCODER] = { .name = "I2S Encoder", diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 61f9d417fd60..8c166a5f338c 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver axg_frddr_dai_drv = { @@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static const char * const axg_frddr_sel_texts[] = { @@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver g12a_frddr_dai_drv = { @@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index ad43cb2a1e3f..d59050914d3c 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(priv->dclk); } -static const struct snd_soc_dai_ops axg_pdm_dai_ops = { - .trigger = axg_pdm_trigger, - .hw_params = axg_pdm_hw_params, - .startup = axg_pdm_startup, - .shutdown = axg_pdm_shutdown, -}; - static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) { const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; @@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + static struct snd_soc_dai_driver axg_pdm_dai_drv = { .name = "PDM", .capture = { @@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &axg_pdm_dai_ops, - .probe = axg_pdm_dai_probe, - .remove = axg_pdm_dai_remove, }; static const struct snd_soc_component_driver axg_pdm_component_drv = { diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index e2cc4c4be758..d86880169075 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_spdifin_ops = { + .probe = axg_spdifin_dai_probe, + .remove = axg_spdifin_dai_remove, .prepare = axg_spdifin_prepare, .startup = axg_spdifin_startup, .shutdown = axg_spdifin_shutdown, @@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) drv->name = "SPDIF Input"; drv->ops = &axg_spdifin_ops; - drv->probe = axg_spdifin_dai_probe; - drv->remove = axg_spdifin_dai_remove; drv->capture.stream_name = "Capture"; drv->capture.channels_min = 1; drv->capture.channels_max = 2; diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 5e5e4c56d505..1c3d433cefd2 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_tdm_iface_ops = { + .probe = axg_tdm_iface_probe_dai, + .remove = axg_tdm_iface_remove_dai, .set_sysclk = axg_tdm_iface_set_sysclk, .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, @@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_PAD, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, [TDM_IFACE_LOOPBACK] = { .name = "TDM Loopback", @@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_LOOPBACK, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, }; diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e9208e74e965..1a0be177b8fe 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = axg_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver axg_toddr_dai_drv = { @@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const char * const axg_toddr_sel_texts[] = { @@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver g12a_toddr_dai_drv = { @@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const struct snd_soc_component_driver g12a_toddr_component_drv = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index ddc667956cf5..6c4503766fdc 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops g12a_toacodec_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = g12a_toacodec_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = { .id = (xid), \ .playback = TOACODEC_STREAM(xname, "Playback", 8), \ .ops = &g12a_toacodec_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOACODEC_OUTPUT(xname, xid) { \ diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 579a04ad4d19..f7ef9aa1eed8 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { .id = (xid), \ .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ .ops = &g12a_tohdmitx_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ -- cgit v1.2.3 From cfacc4d8c04d177911ae2c6601d9c320c5c5c29e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:24 +0000 Subject: ASoC: jz4740: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y1il9m7f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 578af21769c9..517619531615 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { + .probe = jz4740_i2s_dai_probe, .startup = jz4740_i2s_startup, .shutdown = jz4740_i2s_shutdown, .trigger = jz4740_i2s_trigger, @@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver jz4740_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = { }; static struct snd_soc_dai_driver jz4770_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, -- cgit v1.2.3 From dd64a7546dcba40aef17fea52c66fac766902d32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:29 +0000 Subject: ASoC: cirrus: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Alexander Sverdlin Link: https://lore.kernel.org/r/87wmy59m7a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index afc6b5b570ea..522de4b80293 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) #endif static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { + .probe = ep93xx_i2s_dai_probe, .startup = ep93xx_i2s_startup, .shutdown = ep93xx_i2s_shutdown, .hw_params = ep93xx_i2s_hw_params, @@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { static struct snd_soc_dai_driver ep93xx_i2s_dai = { .symmetric_rate = 1, - .probe = ep93xx_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From d7dd3dec11fd2c0e9d689a3d227749b178810409 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:35 +0000 Subject: ASoC: drm/vc4: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8dp9m74.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 5261526d286f..a8dec24b146b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2615,9 +2615,13 @@ static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops vc4_snd_dai_ops = { + .probe = vc4_hdmi_audio_cpu_dai_probe, +}; + static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { .name = "vc4-hdmi-cpu-dai", - .probe = vc4_hdmi_audio_cpu_dai_probe, + .ops = &vc4_snd_dai_ops, .playback = { .stream_name = "Playback", .channels_min = 1, -- cgit v1.2.3 From fda5c5e752aae1b1b8809055b09ba5184507ce5a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:41 +0000 Subject: ASoC: samsung: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt99m6y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 5 ++--- sound/soc/samsung/pcm.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f3d98abd5f0d..3af48c9b5ab7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { + .probe = samsung_i2s_dai_probe, + .remove = samsung_i2s_dai_remove, .trigger = i2s_trigger, .hw_params = i2s_hw_params, .set_fmt = i2s_set_fmt, @@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, for (i = 0; i < num_dais; i++) { dai_drv = &priv->dai_drv[i]; - dai_drv->probe = samsung_i2s_dai_probe; - dai_drv->remove = samsung_i2s_dai_remove; - dai_drv->symmetric_rate = 1; dai_drv->ops = &samsung_i2s_dai_ops; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 335fe5cb9cfc..d2cdc5c8e05b 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { - .set_sysclk = s3c_pcm_set_sysclk, - .set_clkdiv = s3c_pcm_set_clkdiv, - .trigger = s3c_pcm_trigger, - .hw_params = s3c_pcm_hw_params, - .set_fmt = s3c_pcm_set_fmt, -}; - static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) { struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai); @@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .probe = s3c_pcm_dai_probe, + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_DAI_DECLARE \ .symmetric_rate = 1, \ - .probe = s3c_pcm_dai_probe, \ .ops = &s3c_pcm_dai_ops, \ .playback = { \ .channels_min = 2, \ -- cgit v1.2.3 From d656593b3d5218e0ce623cd725e806879e9ce2df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:52 +0000 Subject: ASoC: mediatek: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Trevor Wu Link: https://lore.kernel.org/r/87sf8t9m6n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-dai-etdm.c | 56 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index eedb9165f911..fd4f9f8f032d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_etdm_cal_mclk(afe, freq, dai->id); } -static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { - .startup = mtk_dai_etdm_startup, - .shutdown = mtk_dai_etdm_shutdown, - .hw_params = mtk_dai_etdm_hw_params, - .trigger = mtk_dai_etdm_trigger, - .set_sysclk = mtk_dai_etdm_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, - .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, -}; - -static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { - .startup = mtk_dai_hdmitx_dptx_startup, - .shutdown = mtk_dai_hdmitx_dptx_shutdown, - .hw_params = mtk_dai_hdmitx_dptx_hw_params, - .trigger = mtk_dai_hdmitx_dptx_trigger, - .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, -}; - /* dai driver */ #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000) @@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_sysclk = mtk_dai_etdm_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, + .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, +}; + static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { { .name = "DPTX", @@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_IN", @@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM1_OUT", @@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_OUT", @@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM3_OUT", @@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .rates = MTK_ETDM_RATES, .formats = MTK_ETDM_FORMATS, }, - .ops = &mtk_dai_hdmitx_dptx_ops, - .probe = mtk_dai_etdm_probe, + .ops = &mtk_dai_hdmitx_dptx_ops2, }, }; -- cgit v1.2.3 From bd6af1bc86014f67cbed3804eb6c9bdbfed1b3c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:58 +0000 Subject: ASoC: rockchip: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0od9m6i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 2 +- sound/soc/rockchip/rockchip_i2s_tdm.c | 2 +- sound/soc/rockchip/rockchip_pdm.c | 2 +- sound/soc/rockchip/rockchip_spdif.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 575a0b9b01e9..834fbb5cf810 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { + .probe = rockchip_i2s_dai_probe, .hw_params = rockchip_i2s_hw_params, .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, .set_sysclk = rockchip_i2s_set_sysclk, @@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { }; static struct snd_soc_dai_driver rockchip_i2s_dai = { - .probe = rockchip_i2s_dai_probe, .ops = &rockchip_i2s_dai_ops, .symmetric_rate = 1, }; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 166257c6ae14..d3700f3c98e6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { + .probe = rockchip_i2s_tdm_dai_probe, .hw_params = rockchip_i2s_tdm_hw_params, .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, .set_sysclk = rockchip_i2s_tdm_set_sysclk, @@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = { }; static const struct snd_soc_dai_driver i2s_tdm_dai = { - .probe = rockchip_i2s_tdm_dai_probe, .ops = &rockchip_i2s_tdm_dai_ops, }; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 52f9aae60be8..667f2fa65c3e 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { + .probe = rockchip_pdm_dai_probe, .set_fmt = rockchip_pdm_set_fmt, .trigger = rockchip_pdm_trigger, .hw_params = rockchip_pdm_hw_params, @@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver rockchip_pdm_dai = { - .probe = rockchip_pdm_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 2, diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 0b73fe94e4bb..1a24b78e9e02 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rk_spdif_dai_ops = { + .probe = rk_spdif_dai_probe, .hw_params = rk_spdif_hw_params, .trigger = rk_spdif_trigger, }; static struct snd_soc_dai_driver rk_spdif_dai = { - .probe = rk_spdif_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 89621b57eef451592553227a781d12aa1a6a2556 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:13 +0000 Subject: ASoC: uniphier: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3x9m62.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 161 +++++++++++++++++++++++++++++++++++------- sound/soc/uniphier/aio-ld11.c | 62 +++------------- sound/soc/uniphier/aio-pxs2.c | 55 ++------------- sound/soc/uniphier/aio.h | 10 +-- 4 files changed, 156 insertions(+), 132 deletions(-) diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 4e8d5f7532ba..7c5188477b7c 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops uniphier_aio_i2s_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .set_fmt = uniphier_aio_set_fmt, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops); - -const struct snd_soc_dai_ops uniphier_aio_spdif_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops); - -int uniphier_aio_dai_probe(struct snd_soc_dai *dai) +static int uniphier_aio_dai_probe(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); int i; @@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai) +static int uniphier_aio_dai_remove(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); @@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove); + +static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2); + +const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2); static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) { diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 7b3cf5d751f6..15dbded63804 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMIN2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .capture = { .stream_name = AUD_NAME_PCMIN2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HPCMOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 8, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops, }, { .name = AUD_NAME_EPCMOUT2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_EPCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops2, }, }; diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index 899904f7ffd6..305cb2a1253d 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_AUX, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_IECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_IECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, { .name = AUD_NAME_IECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_IECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, }; diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h index 0b03571aa9f0..09ccb47337fd 100644 --- a/sound/soc/uniphier/aio.h +++ b/sound/soc/uniphier/aio.h @@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai) int uniphier_aiodma_soc_register_platform(struct platform_device *pdev); extern const struct snd_compress_ops uniphier_aio_compress_ops; -int uniphier_aio_dai_probe(struct snd_soc_dai *dai); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai); int uniphier_aio_probe(struct platform_device *pdev); int uniphier_aio_remove(struct platform_device *pdev); -extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops; -extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2; u64 aio_rb_cnt(struct uniphier_aio_sub *sub); u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub); -- cgit v1.2.3 From b396843799ae92bbac30874f18e6a79d5fa736d1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:19 +0000 Subject: ASoC: loongson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o7jh9m5w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_i2s.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index b919f0fe8361..d45228a3a558 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { - .trigger = loongson_i2s_trigger, - .hw_params = loongson_i2s_hw_params, - .set_sysclk = loongson_i2s_set_dai_sysclk, - .set_fmt = loongson_i2s_set_fmt, -}; - static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) { struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev); @@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { + .probe = loongson_i2s_dai_probe, + .trigger = loongson_i2s_trigger, + .hw_params = loongson_i2s_hw_params, + .set_sysclk = loongson_i2s_set_dai_sysclk, + .set_fmt = loongson_i2s_set_fmt, +}; + struct snd_soc_dai_driver loongson_i2s_dai = { .name = "loongson-i2s", - .probe = loongson_i2s_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, -- cgit v1.2.3 From e86cc958cf2d7d8813fd865603d83a2963e87954 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:25 +0000 Subject: ASoC: starfive: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Walker Chen Link: https://lore.kernel.org/r/87msz19m5r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 705f1420097b..8c117794b028 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { - .startup = jh7110_tdm_startup, - .hw_params = jh7110_tdm_hw_params, - .trigger = jh7110_tdm_trigger, - .set_fmt = jh7110_tdm_set_dai_fmt, -}; - static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) { struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); @@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { + .probe = jh7110_tdm_dai_probe, + .startup = jh7110_tdm_startup, + .hw_params = jh7110_tdm_hw_params, + .trigger = jh7110_tdm_trigger, + .set_fmt = jh7110_tdm_set_dai_fmt, +}; + #define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000 #define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = { .formats = JH7110_TDM_FORMATS, }, .ops = &jh7110_tdm_dai_ops, - .probe = jh7110_tdm_dai_probe, .symmetric_rate = 1, }; -- cgit v1.2.3 From 4f1ec3da4e1377b548e2af55586d0f7a92847a96 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:30 +0000 Subject: ASoC: hisilicon: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leel9m5l.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 27219a9e7d0d..dd7d2a077248 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { + .probe = hi6210_i2s_dai_probe, .trigger = hi6210_i2s_trigger, .hw_params = hi6210_i2s_hw_params, .set_fmt = hi6210_i2s_set_fmt, @@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { }; static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { - .probe = hi6210_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 586685f14d9dd16556449ceaa07c2bdc94cbed1b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:36 +0000 Subject: ASoC: codecs/wm*: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu59m5f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 12 ++++++------ sound/soc/codecs/wm5102.c | 6 +++++- sound/soc/codecs/wm5110.c | 8 ++++++-- sound/soc/codecs/wm8994.c | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 36cdf97993a5..9679906c6bd5 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops wm2200_dai_ops = { - .set_fmt = wm2200_set_fmt, - .hw_params = wm2200_hw_params, -}; - static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops wm2200_dai_ops = { + .probe = wm2200_dai_probe, + .set_fmt = wm2200_set_fmt, + .hw_params = wm2200_hw_params, +}; + #define WM2200_RATES SNDRV_PCM_RATE_8000_48000 #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ @@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver wm2200_dai = { .name = "wm2200", - .probe = wm2200_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 3bdbdf3770b5..4ecf07c7448c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id, #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5102_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5102_dai[] = { { .name = "wm5102-aif1", @@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { .rates = WM5102_RATES, .formats = WM5102_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5102_dai_ops, }, { .name = "wm5102-dsp-trace", diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index ad670300de8d..ac1f2c850346 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id, #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5110_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5110_dai[] = { { .name = "wm5110-aif1", @@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-voicectrl", @@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-trace", diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bca3ebe0dac4..a48e904a9740 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = { }; static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = { + .probe = wm8994_aif2_probe, .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, @@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .formats = WM8994_FORMATS, .sig_bits = 24, }, - .probe = wm8994_aif2_probe, .ops = &wm8994_aif2_dai_ops, }, { -- cgit v1.2.3 From 80585b0c6aaabc5a4a8273c2e8e084a4f4d7f62f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:42 +0000 Subject: ASoC: soc-topology: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9p9m5a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ad08d4f75a7b..e783055b6c3a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, 1 : 0; } +static const struct snd_soc_dai_ops tplg_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, } if (pcm->compress) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &tplg_dai_ops; /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); -- cgit v1.2.3 From e22a907d66b679d2ce86fe73fbd47760981b30cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:47 +0000 Subject: ASoC: codecs/cs47lxx: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Charles Keepax Link: https://lore.kernel.org/r/87h6p99m55.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l15.c | 6 +++++- sound/soc/codecs/cs47l24.c | 8 ++++++-- sound/soc/codecs/cs47l35.c | 8 ++++++-- sound/soc/codecs/cs47l85.c | 8 ++++++-- sound/soc/codecs/cs47l90.c | 8 ++++++-- sound/soc/codecs/cs47l92.c | 6 +++++- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index a6538dab6639..1245e1a4f2a5 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l15_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l15_dai[] = { { .name = "cs47l15-aif1", @@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l15_dai_ops, }, { .name = "cs47l15-dsp-trace", diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index a07b621d463e..cfa1d34f6ebd 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id, #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops cs47l24_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l24_dai[] = { { .name = "cs47l24-aif1", @@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-voicectrl", @@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-trace", diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index c05c80c16c84..a953f2ede1ee 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l35_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l35_dai[] = { { .name = "cs47l35-aif1", @@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-voicectrl", @@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-trace", diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index dd7997a53e70..827685481859 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l85_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l85_dai[] = { { .name = "cs47l85-aif1", @@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-voicectrl", @@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-trace", diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index cdd5e7e20b5d..2c9a5372cf51 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l90_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l90_dai[] = { { .name = "cs47l90-aif1", @@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-voicectrl", @@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-trace", diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index bc4d311d4778..352deeaff1ca 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l92_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l92_dai[] = { { .name = "cs47l92-aif1", @@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l92_dai_ops, }, { .name = "cs47l92-dsp-trace", -- cgit v1.2.3 From 878b5fee6e2296685f459148ab82c6a3f300bfe1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:53 +0000 Subject: ASoC: codecs/cx2072x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4t9m4y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 082231088a26..f8b128084015 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops cx2072x_dai_ops2 = { + .probe = cx2072x_dsp_dai_probe, + .set_sysclk = cx2072x_set_dai_sysclk, + .set_fmt = cx2072x_set_dai_fmt, + .hw_params = cx2072x_hw_params, + .set_bclk_ratio = cx2072x_set_dai_bclk_ratio, +}; + #define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { @@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { { /* plabayck only, return echo reference to Conexant DSP chip */ .name = "cx2072x-dsp", .id = CX2072X_DAI_DSP, - .probe = cx2072x_dsp_dai_probe, .playback = { .stream_name = "DSP Playback", .channels_min = 2, @@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .rates = CX2072X_RATES_DSP, .formats = CX2072X_FORMATS, }, - .ops = &cx2072x_dai_ops, + .ops = &cx2072x_dai_ops2, }, { /* plabayck only, return echo reference through I2S TX */ .name = "cx2072x-aec", -- cgit v1.2.3 From 2edc4a2cc11160f4729d28094952fc906b74ca64 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:58 +0000 Subject: ASoC: codecs/hdmi-codec: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkd9m4t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d21f69f05342..13689e718d36 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -723,24 +723,6 @@ static u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_AC97; -static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - .auto_selectable_formats = &hdmi_codec_formats, - .num_auto_selectable_formats = 1, -}; - -static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .mute_stream = hdmi_codec_mute, -}; - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ @@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .probe = hdmi_dai_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .set_fmt = hdmi_codec_i2s_set_fmt, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, +}; + +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .probe = hdmi_dai_spdif_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, +}; + static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_spdif_probe, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, -- cgit v1.2.3 From 446b31e894935ebbcf84302061a4e0e2efb2368f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:59:03 +0000 Subject: ASoC: soc-dai.h: remove unused call back functions Now, all drivers are using ops call backs. Let's remove unused other call back functions. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzx9m4o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 13 ------------- sound/soc/soc-core.c | 25 ------------------------- 2 files changed, 38 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 85f897fea21a..5fcfba47d98c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -414,15 +414,6 @@ struct snd_soc_dai_driver { struct snd_soc_dobj dobj; struct of_phandle_args *dai_args; - /* DAI driver callbacks */ - int (*probe)(struct snd_soc_dai *dai); - int (*remove)(struct snd_soc_dai *dai); - /* compress dai */ - int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); - /* Optional Callback used at pcm creation*/ - int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); - /* ops */ const struct snd_soc_dai_ops *ops; const struct snd_soc_cdai_ops *cops; @@ -433,10 +424,6 @@ struct snd_soc_dai_driver { unsigned int symmetric_rate:1; unsigned int symmetric_channels:1; unsigned int symmetric_sample_bits:1; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* for Playback/Capture */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7dbf37e0ba2f..a5b96c17633a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,7 +2510,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; - struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2539,30 +2538,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; - /* REMOVE ME */ - if (dai_drv->probe || - dai_drv->remove || - dai_drv->compress_new || - dai_drv->pcm_new || - dai_drv->probe_order || - dai_drv->remove_order) { - - ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); - if (!ops) - return NULL; - if (dai_drv->ops) - memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); - - ops->probe = dai_drv->probe; - ops->remove = dai_drv->remove; - ops->compress_new = dai_drv->compress_new; - ops->pcm_new = dai_drv->pcm_new; - ops->probe_order = dai_drv->probe_order; - ops->remove_order = dai_drv->remove_order; - - dai_drv->ops = ops; - } - dai->component = component; dai->dev = dev; dai->driver = dai_drv; -- cgit v1.2.3 From b39eee2754e9fbcbbdd866c1aad59575d8c4342e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 13 Aug 2023 08:34:58 +0100 Subject: ASoC: ak4613: Simplify probe() Simpilfy probe() by replacing of_device_get_match_data() and id lookup for retrieving match data by i2c_get_match_data(). While at it, drop unused local variable np from probe(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230813073458.59606-1-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index ad56caec9dac..619a817ee91c 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv, static int ak4613_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; - struct device_node *np = dev->of_node; const struct regmap_config *regmap_cfg; struct regmap *regmap; struct ak4613_priv *priv; - regmap_cfg = NULL; - if (np) - regmap_cfg = of_device_get_match_data(dev); - else { - const struct i2c_device_id *id = - i2c_match_id(ak4613_i2c_id, i2c); - regmap_cfg = (const struct regmap_config *)id->driver_data; - } - + regmap_cfg = i2c_get_match_data(i2c); if (!regmap_cfg) return -EINVAL; -- cgit v1.2.3 From 11e756cc85fac43e2025306ad6aea80114cc7e98 Mon Sep 17 00:00:00 2001 From: Guiting Shen Date: Sun, 13 Aug 2023 20:55:20 +0800 Subject: ASoC: tlv320aic32x4: Fix the divide by zero The value of register(NDAC,MDAC,NADC,MADC,BCLKN) maybe zero lead to divide by zero in clk_aic32x4_div_recalc_rate().And the rate should be divide by 128 if the value was zero in this function according to the datasheet. Add the macro AIC32X4_DIV_MAX to present the 128 and return 0 if failing to read the value of register. Signed-off-by: Guiting Shen Link: https://lore.kernel.org/r/20230813125520.11067-1-aarongt.shen@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4-clk.c | 16 +++++++++++----- sound/soc/codecs/tlv320aic32x4.h | 5 +++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index c116e82f712d..5c0a76a4a106 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, u8 divisor; divisor = DIV_ROUND_UP(parent_rate, rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; return regmap_update_bits(div->regmap, div->reg, @@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, unsigned long divisor; divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); @@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); - unsigned int val; + int err; + + err = regmap_read(div->regmap, div->reg, &val); + if (err) + return 0; - regmap_read(div->regmap, div->reg, &val); + val &= AIC32X4_DIV_MASK; + if (!val) + val = AIC32X4_DIV_MAX; - return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK); + return DIV_ROUND_UP(parent_rate, val); } static const struct clk_ops aic32x4_div_ops = { diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 4de5bd9e8cc5..d6101ce73f80 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_REFPOWERUP_120MS 0x07 /* Common mask and enable for all of the dividers */ -#define AIC32X4_DIVEN BIT(7) -#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIVEN BIT(7) +#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIV_MAX 128 /* Clock Limits */ #define AIC32X4_MAX_DOSR_FREQ 6200000 -- cgit v1.2.3 From b0a4c7f5921d9c2998bdd767a93d995786d72adc Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Thu, 10 Aug 2023 19:47:37 +0800 Subject: ASoC: tas5805m: Use devm_kmemdup to replace devm_kmalloc + memcpy Use the helper function devm_kmemdup() rather than duplicating its implementation, which helps to enhance code readability. Signed-off-by: Li Zetao Link: https://lore.kernel.org/r/20230810114738.2103792-2-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas5805m.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index aca3756ffab6..3b53eba38a0b 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -520,12 +520,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) } tas5805m->dsp_cfg_len = fw->size; - tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL); + tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL); if (!tas5805m->dsp_cfg_data) { release_firmware(fw); return -ENOMEM; } - memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size); release_firmware(fw); -- cgit v1.2.3 From 29681184da28babc990a66e197d27ab98f2027af Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Thu, 10 Aug 2023 19:47:38 +0800 Subject: ASoC: SOF: ipc3: Use devm_kmemdup to replace devm_kmalloc + memcpy Use the helper function devm_kmemdup() rather than duplicating its implementation, which helps to enhance code readability. Signed-off-by: Li Zetao Reviewed-by: Luca Ceresoli Link: https://lore.kernel.org/r/20230810114738.2103792-3-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 33df028d4854..fb40378ad084 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -567,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev, /* create read-only cc_version debugfs to store compiler version info */ /* use local copy of the cc_version to prevent data corruption */ if (sdev->first_boot) { - sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size, - GFP_KERNEL); - + sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL); if (!sdev->cc_version) return -ENOMEM; - memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size); ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version, cc->ext_hdr.hdr.size, "cc_version", 0444); -- cgit v1.2.3 From 273bc8bf2227108ed2851bea71786a026e34ecbb Mon Sep 17 00:00:00 2001 From: Ajye Huang Date: Fri, 4 Aug 2023 16:56:48 +0800 Subject: ASoC: Intel: Add rpl_nau8318_8825 driver Boards were using this in older kernels before adl and rpl ids were split. Add this back to maintain support. Signed-off-by: Ajye Huang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230804085648.3721416-1-ajye_huang@compal.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 10 ++++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 4fc6e1c6aef3..46b7ecf6f9f1 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -684,6 +684,16 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_nau8318_8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_NAU8318_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 4eefdb2dd45c..1dd699181765 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -351,6 +351,11 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { .codecs = {"RTL1019"} }; +static const struct snd_soc_acpi_codecs rpl_nau8318_amp = { + .num_codecs = 1, + .codecs = {"NVTN2012"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -373,6 +378,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_max98373_amp, .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", }, + { + .id = "10508825", + .drv_name = "rpl_nau8318_8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_nau8318_amp, + .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", + }, { .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_rt1019_rt5682", -- cgit v1.2.3 From 62cc82e6486b9b66b340bbf5fb38b0171fb56a7f Mon Sep 17 00:00:00 2001 From: mnlife Date: Fri, 11 Aug 2023 22:25:11 +0800 Subject: ASoC: soc-jack: calling snd_soc_jack_report causes a null pointer access When snd_soc_card_jack_new is not called or the call fails, calling this function causes a null pointer access Signed-off-by: mnlife Link: https://lore.kernel.org/r/20230811142511.6570-1-mnlife@126.com Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index f951acb2ce36..b2cc13b9c77b 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -37,7 +37,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_jack_pin *pin; unsigned int sync = 0; - if (!jack) + if (!jack || !jack->jack) return; trace_snd_soc_jack_report(jack, mask, status); -- cgit v1.2.3 From f7f4a5ad8e11de4edb7b62d099f0501c8610c92b Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 14 Aug 2023 18:23:24 -0500 Subject: ASoC: dapm: Add a flag for not having widget name in kcontrol name The existing soc-dapm code may add a prefix to control names, which in some cases is useful but in others leads to long and confusing kcontrol names such as "gain 2.1 Main Playback Volume". This patch suggests an added flag to prevent the widget name prefix from being added. That flag will be set in the topology file on a per-widget basis. The flag no_wname_in_kcontrol_name is added to struct snd_soc_dapm_widget, and the logic in dapm_create_or_share_kcontrol() is changed to not to add widget name if the flag is set. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Jyri Sarha Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814232325.86397-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + sound/soc/soc-dapm.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2e38dff16779..d2faec9a323e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -650,6 +650,7 @@ struct snd_soc_dapm_widget { unsigned char power_checked:1; /* power checked this run */ unsigned char is_supply:1; /* Widget is a supply type widget */ unsigned char is_ep:2; /* Widget is a endpoint type widget */ + unsigned char no_wname_in_kcontrol_name:1; /* No widget name prefix in kcontrol name */ int subseq; /* sort within widget type */ int (*power_check)(struct snd_soc_dapm_widget *w); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3091e8160bad..f07e83678373 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -916,6 +916,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, return -EINVAL; } } + if (w->no_wname_in_kcontrol_name) + wname_in_long_name = false; if (wname_in_long_name && kcname_in_long_name) { /* -- cgit v1.2.3 From 56ce7b791b787e0aee19601e422f13a18d4eafe7 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 14 Aug 2023 18:23:25 -0500 Subject: ASoC: SOF: topology: Add a token for dropping widget name in kcontrol name Adds SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME token, and copies the token's tuple value to the no_wname_in_kcontrol_name flag in struct snd_soc_dapm_widget. If the tuple value for the token in the topology is true, then the widget name is not added to the mixer name. In practice "gain.2.1 Post Mixer Analog Playback Volume" becomes just "Post Mixer Analog Playback Volume". Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Jyri Sarha Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814232325.86397-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 6 +++++- sound/soc/sof/topology.c | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index e9ec7e4eb982..453cab2a1209 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -99,7 +99,11 @@ #define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME 414 #define SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS 415 #define SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS 416 - +/* + * The token value is copied to the dapm_widget's + * no_wname_in_kcontrol_name. + */ +#define SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME 417 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index be63ba06762f..a3a3af252259 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1367,6 +1367,20 @@ err: return ret; } +static int get_w_no_wname_in_long_name(void *elem, void *object, u32 offset) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + struct snd_soc_dapm_widget *w = object; + + w->no_wname_in_kcontrol_name = !!le32_to_cpu(velem->value); + return 0; +} + +static const struct sof_topology_token dapm_widget_tokens[] = { + {SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME, SND_SOC_TPLG_TUPLE_TYPE_BOOL, + get_w_no_wname_in_long_name, 0} +}; + /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1397,6 +1411,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ida_init(&swidget->output_queue_ida); ida_init(&swidget->input_queue_ida); + ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, ARRAY_SIZE(dapm_widget_tokens), + priv->array, le32_to_cpu(priv->size)); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n", + w->name); + goto widget_free; + } + ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens, ARRAY_SIZE(comp_pin_tokens), priv->array, le32_to_cpu(priv->size)); -- cgit v1.2.3 From fc8b9d05a01f7cd98e0805aa773603b07515de06 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:55 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for sof_es8336 in RPL match table. Adding support for ES83x6 codec in RPL match table. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 4eefdb2dd45c..1f503c734ab5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -331,6 +331,11 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs rpl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -380,6 +385,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_rt1019p_amp, .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); -- cgit v1.2.3 From fbc82c016d96aa4a2d99587cae2b78d5c5a59ea7 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:56 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for HDMI_In capture support in RPL match table Adding HDMI-In capture via I2S feature support in RPL platfroms. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_es8336.c | 10 ++++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index d6c38d8ea2ff..f8a3e8a91761 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -798,6 +798,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "rpl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 1f503c734ab5..3db0dc4ca66f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -356,6 +356,11 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { .codecs = {"RTL1019"} }; +static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -385,6 +390,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_rt1019p_amp, .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "rpl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_lt6911_hdmi, + .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &rpl_essx_83x6, .drv_name = "sof-essx8336", -- cgit v1.2.3 From fec75606f48f6c85eca8a9e868e41fb657abd1ca Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 14 Aug 2023 18:13:57 -0500 Subject: ASoC: Intel: soc-acpi: add support for Dell SKU0C87 devices This patch adds the acpi match table for Dell SKU0C87 devices, the codec layout is: SDW0: RT714 DMIC SDW1: RT1318 Speaker SDW2: RT1318 Speaker Note that there is no jack codec on SKU0C87 devices. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Chao Song Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index ed9821adc1d9..0304246d2922 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -161,6 +161,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { + { + .adr = 0x000130025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1318-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { + { + .adr = 0x000232025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1318-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { + { + .adr = 0x000030025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { { .adr = 0x000130025D071401ull, @@ -232,6 +259,25 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_group1_adr), + .adr_d = rt1318_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1318_2_group1_adr), + .adr_d = rt1318_2_group1_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = { { .adr = 0x000230019F836300ull, @@ -298,6 +344,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", }, + { + .link_mask = GENMASK(2, 0), + .links = mtl_sdw_rt1318_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg" + }, { .link_mask = GENMASK(3, 0), .links = mtl_3_in_1_sdca, -- cgit v1.2.3 From f7555da71ef6eb9d289173d94ec2cc9d15061f33 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:58 -0500 Subject: ASoC: Intel: RPL: Add entry for HDMI-In capture support on non-I2S codec boards. Adding HDMI-In capture support for the RPL products doesn't have onboard I2S codec.but need to support HDMI-In capture via I2S and audio playback through HDMI/DP monitor. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 9 +++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 0aef718e82b2..5aa16fd3939b 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -472,6 +472,15 @@ static const struct platform_device_id board_ids[] = { SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, + { + .name = "rpl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_NO_OF_HDMI_PLAYBACK(3) | + SOF_HDMI_PLAYBACK_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 3db0dc4ca66f..91b0648799b2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -405,6 +405,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "INTC10B0", + .drv_name = "rpl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); -- cgit v1.2.3 From c5556d8651b4c58e0d9894be5a0188c9c90ce899 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 14 Aug 2023 18:42:35 -0500 Subject: ASoC: SOF: remove duplicate code due to merge Commit 81113108491e ("ASoC: Merge up fixes") added the same code twice, remove the extra call. Signed-off-by: Pierre-Louis Bossart Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230814234235.87268-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index b43663822613..633f6040d712 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1734,9 +1734,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); - /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); - /* copy IPC data */ memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); if (gtw_cfg_config_length) -- cgit v1.2.3 From a942409c97ce12c2a4811b538568b1342d91e56c Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 14 Aug 2023 18:15:19 -0500 Subject: ASoC: SOF: Intel: Refactor code for HDA stream creation Existing HDA stream creation is split into two for loops for capture and playback, but most of the code in the two for loops are duplicated. This patch refactors HDA stream creation with a single for loop, thus remove code duplication. No functional change in this patch. Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Signed-off-by: Chao Song Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231519.79051-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 68 +++++----------------------------------- 1 file changed, 8 insertions(+), 60 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b13acb959653..0b0087abcc50 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -869,8 +869,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; } - /* create capture streams */ - for (i = 0; i < num_capture; i++) { + /* create capture and playback streams */ + for (i = 0; i < num_total; i++) { struct sof_intel_hda_stream *hda_stream; hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), @@ -909,69 +909,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) hstream->index = i; sd_offset = SOF_STREAM_SD_OFFSET(hstream); hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i + 1; hstream->opened = false; hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_CAPTURE; - /* memory alloc for stream BDL */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - HDA_DSP_BDL_SIZE, &hstream->bdl); - if (ret < 0) { - dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); - return -ENOMEM; - } - hstream->posbuf = (__le32 *)(bus->posbuf.area + - (hstream->index) * 8); - - list_add_tail(&hstream->list, &bus->stream_list); - } - - /* create playback streams */ - for (i = num_capture; i < num_total; i++) { - struct sof_intel_hda_stream *hda_stream; - - hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), - GFP_KERNEL); - if (!hda_stream) - return -ENOMEM; - - hda_stream->sdev = sdev; - - hext_stream = &hda_stream->hext_stream; - - if (sdev->bar[HDA_DSP_PP_BAR]) { - hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; - - hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + - SOF_HDA_PPLC_INTERVAL * i; - } - - hstream = &hext_stream->hstream; - - /* do we support SPIB */ - if (sdev->bar[HDA_DSP_SPIB_BAR]) { - hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_SPIB; - - hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_MAXFIFO; + if (i < num_capture) { + hstream->stream_tag = i + 1; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; + } else { + hstream->stream_tag = i - num_capture + 1; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; } - hstream->bus = bus; - hstream->sd_int_sta_mask = 1 << i; - hstream->index = i; - sd_offset = SOF_STREAM_SD_OFFSET(hstream); - hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i - num_capture + 1; - hstream->opened = false; - hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; - /* mem alloc for stream BDL */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, HDA_DSP_BDL_SIZE, &hstream->bdl); -- cgit v1.2.3 From 62ddad4238a0250aa9cedade127c39aac9d26d45 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 15 Aug 2023 13:48:25 +0100 Subject: ASoC: wm_adsp: Support powering-up DSP without trying to load firmware Add a flag to wm_adsp_power_up() that indicates whether it should attempt to find and load firmware files. This is to support DSPs that have built-in firmware that may already have been patched (for example, by the BIOS). In that case the patch must not be overwritten because that could corrupt the running firmware. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230815124826.5447-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 4 ++-- sound/soc/codecs/wm_adsp.c | 16 +++++++++------- sound/soc/codecs/wm_adsp.h | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 80e7fddae926..98cfcae554af 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -656,7 +656,7 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) int ret; /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + ret = wm_adsp_power_up(&cs35l56->dsp, true); if (ret) dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); else @@ -686,7 +686,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) goto err; /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + ret = wm_adsp_power_up(&cs35l56->dsp, true); if (ret) { dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 13f500fa9a5f..6fc34f41b175 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -998,7 +998,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); -int wm_adsp_power_up(struct wm_adsp *dsp) +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware) { int ret = 0; char *wmfw_filename = NULL; @@ -1006,11 +1006,13 @@ int wm_adsp_power_up(struct wm_adsp *dsp) char *coeff_filename = NULL; const struct firmware *coeff_firmware = NULL; - ret = wm_adsp_request_firmware_files(dsp, - &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); - if (ret) - return ret; + if (load_firmware) { + ret = wm_adsp_request_firmware_files(dsp, + &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret) + return ret; + } ret = cs_dsp_power_up(&dsp->cs_dsp, wmfw_firmware, wmfw_filename, @@ -1037,7 +1039,7 @@ static void wm_adsp_boot_work(struct work_struct *work) struct wm_adsp, boot_work); - wm_adsp_power_up(dsp); + wm_adsp_power_up(dsp, true); } int wm_adsp_early_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3044f964ac14..067d807a7ca8 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -91,7 +91,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int wm_adsp_power_up(struct wm_adsp *dsp); +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware); void wm_adsp_power_down(struct wm_adsp *dsp); irqreturn_t wm_adsp2_bus_error(int irq, void *data); -- cgit v1.2.3 From 67bd793ba5e0984ecb7ee4407c2f79d159e305ff Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 15 Aug 2023 13:48:26 +0100 Subject: ASoC: cs35l56: Don't overwrite a patched firmware Only attempt to download wmfw/bin files to a non-secured part if it reports FIRMWARE_MISSING. If FIRMWARE_MISSING is false the firmware has already been patched and overwriting the patch could corrupt the running firmware. For a secured part the wmfw/bin can be downloaded even if FIRMWARE_MISSING is false, because they will only patch tunings. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230815124826.5447-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 98cfcae554af..3a9ec8724cc1 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -665,8 +665,17 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) static void cs35l56_patch(struct cs35l56_private *cs35l56) { + unsigned int firmware_missing; int ret; + ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing); + if (ret) { + dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + return; + } + + firmware_missing &= CS35L56_FIRMWARE_MISSING; + /* * Disable SoundWire interrupts to prevent race with IRQ work. * Setting sdw_irq_no_unmask prevents the handler re-enabling @@ -685,8 +694,12 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) if (ret) goto err; - /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp, true); + /* + * Use wm_adsp to load and apply the firmware patch and coefficient files, + * but only if firmware is missing. If firmware is already patched just + * power-up wm_adsp without downloading firmware. + */ + ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing); if (ret) { dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; -- cgit v1.2.3 From 66de320b0214a60095287ba1afa09e870d8cdbe5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:02 +0200 Subject: ASoC: codecs: tlv320aic32x4: Fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: tlv320aic32x4.c:1352:18: error: cast to smaller integer type 'enum aic32x4_type' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index ffe1828a4b7e..6829834a412f 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1349,7 +1349,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) return -ENOMEM; aic32x4->dev = dev; - aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev); + aic32x4->type = (uintptr_t)dev_get_drvdata(dev); dev_set_drvdata(dev, aic32x4); -- cgit v1.2.3 From 5a1803324949f4ebdf6e887b59e0e89afc3ee0bb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:03 +0200 Subject: ASoC: codecs: wm8904: Fix Wvoid-pointer-to-enum-cast warning 'devtype' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: wm8904.c:2205:21: error: cast to smaller integer type 'enum wm8904_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 60319b468fb2..829bf055622a 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2202,7 +2202,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) match = of_match_node(wm8904_of_match, i2c->dev.of_node); if (match == NULL) return -EINVAL; - wm8904->devtype = (enum wm8904_type)match->data; + wm8904->devtype = (uintptr_t)match->data; } else { const struct i2c_device_id *id = i2c_match_id(wm8904_i2c_id, i2c); -- cgit v1.2.3 From 49a4a8d1261230378a8931d0859329057686b6eb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:04 +0200 Subject: ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning 'version' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rockchip_pdm.c:587:18: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 667f2fa65c3e..4756cfc23218 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -584,7 +584,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) match = of_match_device(rockchip_pdm_match, &pdev->dev); if (match) - pdm->version = (enum rk_pdm_version)match->data; + pdm->version = (uintptr_t)match->data; if (pdm->version == RK_PDM_RK3308) { pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m"); -- cgit v1.2.3 From 7ac1102b227b36550452b663fd39ab1c09378a95 Mon Sep 17 00:00:00 2001 From: Vlad Karpovich Date: Tue, 15 Aug 2023 12:29:08 -0500 Subject: firmware: cs_dsp: Fix new control name check Before adding a new FW control, its name is checked against existing controls list. But the string length in strncmp used to compare controls names is taken from the list, so if beginnings of the controls are matching, then the new control is not created. For example, if CAL_R control already exists, CAL_R_SELECTED is not created. The fix is to compare string lengths as well. Fixes: 6477960755fb ("ASoC: wm_adsp: Move check for control existence") Signed-off-by: Vlad Karpovich Link: https://lore.kernel.org/r/20230815172908.3454056-1-vkarpovi@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 6a9aa97373d3..49b70c70dc69 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -978,7 +978,8 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, ctl->alg_region.alg == alg_region->alg && ctl->alg_region.type == alg_region->type) { if ((!subname && !ctl->subname) || - (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) { + (subname && (ctl->subname_len == subname_len) && + !strncmp(ctl->subname, subname, ctl->subname_len))) { if (!ctl->enabled) ctl->enabled = 1; return 0; -- cgit v1.2.3 From a06ce12efb63bad77bd4a6cedc180f181a651920 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:49 +0200 Subject: ASoC: dt-bindings: Add common sound card properties Almost every board machine / sound cards has "audio-routing" and "model" properties, so move them to common schema to have only one definition of these properties. For amlogic,gx-sound-card, drop the minItems: 2 from the "audio-routing", because any limit here - lower or upper- is rather meaningless. This will also fix `dtbs_check` warnings like: meson-gxm-s912-libretech-pc.dtb: sound: audio-routing: ['AU2 INL', 'ACODEC LOLN', 'AU2 INR', 'ACODEC LORN', '7J4-14 LEFT', 'AU2 OUTL', '7J4-11 RIGHT', 'AU2 OUTR'] is too long Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/amlogic,axg-sound-card.yaml | 15 +++--------- .../bindings/sound/amlogic,gx-sound-card.yaml | 17 ++++---------- .../devicetree/bindings/sound/fsl,rpmsg.yaml | 17 ++++---------- .../bindings/sound/google,sc7180-trogdor.yaml | 17 ++++---------- .../bindings/sound/google,sc7280-herobrine.yaml | 17 ++++---------- .../devicetree/bindings/sound/imx-audio-card.yaml | 18 ++++----------- .../bindings/sound/sound-card-common.yaml | 27 ++++++++++++++++++++++ 7 files changed, 50 insertions(+), 78 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/sound-card-common.yaml diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml index bf1234550343..5db718e4d0e7 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml @@ -9,6 +9,9 @@ title: Amlogic AXG sound card maintainers: - Jerome Brunet +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: amlogic,axg-sound-card @@ -17,23 +20,12 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array description: list of auxiliary devices - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - patternProperties: "^dai-link-[0-9]+$": type: object @@ -108,7 +100,6 @@ patternProperties: - sound-dai required: - - model - dai-link-0 unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index b358fd601ed3..d4277d342e69 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -9,6 +9,9 @@ title: Amlogic GX sound card maintainers: - Jerome Brunet +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: items: @@ -18,14 +21,6 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array description: list of auxiliary devices - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - minItems: 2 - description: |- - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array minItems: 2 @@ -33,10 +28,6 @@ properties: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - patternProperties: "^dai-link-[0-9]+$": type: object @@ -86,7 +77,7 @@ required: - model - dai-link-0 -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml index 6df0e03a1d4b..188f38baddec 100644 --- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -17,6 +17,9 @@ description: | such as SAI, MICFIL, .etc through building rpmsg channels between Cortex-A and Cortex-M. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: @@ -27,10 +30,6 @@ properties: - fsl,imx8ulp-rpmsg-audio - fsl,imx93-rpmsg-audio - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - clocks: items: - description: Peripheral clock for register access @@ -66,13 +65,6 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle to a node of audio codec - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: | - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - fsl,enable-lpa: $ref: /schemas/types.yaml#/definitions/flag description: enable low power audio path. @@ -101,9 +93,8 @@ properties: required: - compatible - - model -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml index ba5b7728cf33..bac940553965 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml @@ -13,23 +13,15 @@ maintainers: description: This binding describes the SC7180 sound card which uses LPASS for audio. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - google,sc7180-trogdor - google,sc7180-coachz - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - "#address-cells": const: 1 @@ -86,11 +78,10 @@ patternProperties: required: - compatible - - model - "#address-cells" - "#size-cells" -additionalProperties: false +unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml index 0b1a01a4c14e..ec4b6e547ca6 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml @@ -13,22 +13,14 @@ maintainers: description: This binding describes the SC7280 sound card which uses LPASS for audio. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - google,sc7280-herobrine - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - "#address-cells": const: 1 @@ -97,11 +89,10 @@ patternProperties: required: - compatible - - model - "#address-cells" - "#size-cells" -additionalProperties: false +unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml index b6f5d486600e..f7ad5ea2491e 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml @@ -9,23 +9,14 @@ title: NXP i.MX audio sound card. maintainers: - Shengjiu Wang +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - fsl,imx-audio-card - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. Valid names could be power supplies, - MicBias of codec and the jacks on the board. - patternProperties: ".*-dai-link$": description: @@ -84,9 +75,8 @@ patternProperties: required: - compatible - - model -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/sound-card-common.yaml b/Documentation/devicetree/bindings/sound/sound-card-common.yaml new file mode 100644 index 000000000000..3a941177f684 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sound-card-common.yaml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sound-card-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Board Sound Card Common Properties + +maintainers: + - Mark Brown + +properties: + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. Each entry is a + pair of strings, the first being the connection's sink, the second + being the connection's source. + + model: + $ref: /schemas/types.yaml#/definitions/string + description: User specified audio sound card name + +required: + - model + +additionalProperties: true -- cgit v1.2.3 From 34e7bf1acc33da5b45ded94f459a6e30d4c6acdc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:50 +0200 Subject: ASoC: dt-bindings: mediatek,mt8188-mt6359: use common sound card The mediatek,mt8188-mt6359 Linux sound machine driver requires the "model" property, so binding was incomplete. Reference the common sound card properties to fix that which also allows to remove duplicated property definitions. Leave the relevant parts of "audio-routing" description. Reviewed-by: Rob Herring Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Krzysztof Kozlowski Acked-by: Trevor Wu Link: https://lore.kernel.org/r/20230810063300.20151-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/mediatek,mt8188-mt6359.yaml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml index 05e532b5d50a..43b3b67bdf3b 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml @@ -9,23 +9,19 @@ title: MediaTek MT8188 ASoC sound card maintainers: - Trevor Wu +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - mediatek,mt8188-mt6359-evb - mediatek,mt8188-nau8825 - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: - A list of the connections between audio components. Each entry is a - sink/source pair of strings. Valid names could be the input or output - widgets of audio components, power supplies, MicBias of codec and the - software switch. + Valid names could be the input or output widgets of audio components, + power supplies, MicBias of codec and the software switch. mediatek,platform: $ref: /schemas/types.yaml#/definitions/phandle @@ -86,7 +82,7 @@ patternProperties: required: - link-name -additionalProperties: false +unevaluatedProperties: false required: - compatible @@ -96,6 +92,7 @@ examples: - | sound { compatible = "mediatek,mt8188-mt6359-evb"; + model = "MT6359-EVB"; mediatek,platform = <&afe>; pinctrl-names = "default"; pinctrl-0 = <&aud_pins_default>; -- cgit v1.2.3 From d63cff2ba4d6cb9eed12508469bf8c1b207be4f1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:51 +0200 Subject: ASoC: dt-bindings: samsung,aries-wm8994: use common sound card Reference the common sound card properties and deprecate the custom "samsung,audio-routing" in favor of generic one. This allows to remove "model" property and make the binding closer to other sounds cards. Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung,aries-wm8994.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml index 447e013f6e17..5ea0819a261a 100644 --- a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml @@ -9,6 +9,9 @@ title: Samsung Aries audio complex with WM8994 codec maintainers: - Jonathan Bakker +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: @@ -17,10 +20,6 @@ properties: # Without FM radio and modem slave - samsung,fascinate4g-wm8994 - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - cpu: type: object additionalProperties: false @@ -46,6 +45,7 @@ properties: samsung,audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array + deprecated: true description: | List of the connections between audio components; each entry is a pair of strings, the first being the @@ -56,6 +56,7 @@ properties: or FM In For samsung,fascinate4g-wm8994: HP, SPK, RCV, LINE, Main Mic, or HeadsetMic + Deprecated, use audio-routing. extcon: description: Extcon phandle for dock detection @@ -87,10 +88,9 @@ properties: required: - compatible - - model - cpu - codec - - samsung,audio-routing + - audio-routing - extcon - main-micbias-supply - headset-micbias-supply @@ -98,7 +98,7 @@ required: - headset-detect-gpios - headset-key-gpios -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -121,7 +121,7 @@ examples: headset-detect-gpios = <&gph0 6 GPIO_ACTIVE_HIGH>; headset-key-gpios = <&gph3 6 GPIO_ACTIVE_HIGH>; - samsung,audio-routing = + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", -- cgit v1.2.3 From e1d776441d7e19cd98d74bb204713940eb6951be Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:52 +0200 Subject: ASoC: dt-bindings: samsung,midas-audio: use common sound card Reference the common sound card properties and deprecate the custom "samsung,audio-routing" in favor of generic one. This allows to remove "model" property and make the binding closer to other sounds cards. Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-4-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung,midas-audio.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index 31095913e330..6ec80f529d84 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -9,14 +9,13 @@ title: Samsung Midas audio complex with WM1811 codec maintainers: - Sylwester Nawrocki +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: samsung,midas-audio - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - cpu: type: object additionalProperties: false @@ -38,6 +37,7 @@ properties: - sound-dai samsung,audio-routing: + deprecated: true $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: | List of the connections between audio components; each entry is @@ -45,6 +45,7 @@ properties: being the connection's source; valid names for sources and sinks are the WM1811's pins (as documented in its binding), and the jacks on the board: HP, SPK, Main Mic, Sub Mic, Headset Mic. + Deprecated, use audio-routing. mic-bias-supply: description: Supply for the micbias on the Main microphone @@ -62,14 +63,13 @@ properties: required: - compatible - - model - cpu - codec - - samsung,audio-routing + - audio-routing - mic-bias-supply - submic-bias-supply -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -84,7 +84,7 @@ examples: mic-bias-supply = <&mic_bias_reg>; submic-bias-supply = <&submic_bias_reg>; - samsung,audio-routing = + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", -- cgit v1.2.3 From 5ddff831f064ee300351ffdd92bfde1e17c88861 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:53 +0200 Subject: ASoC: dt-bindings: samsung,odroid: use common sound card Reference the common sound card properties and deprecate the custom "samsung,audio-routing" in favor of generic one. This allows to remove "model" property and make the binding closer to other sounds cards. Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-5-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung,odroid.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml index c6751c40e63f..b77284e3e26a 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml @@ -10,6 +10,9 @@ maintainers: - Krzysztof Kozlowski - Sylwester Nawrocki +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: oneOf: @@ -24,10 +27,6 @@ properties: - const: samsung,odroid-xu4-audio deprecated: true - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - assigned-clock-parents: true assigned-clock-rates: true assigned-clocks: true @@ -52,6 +51,7 @@ properties: samsung,audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array + deprecated: true description: | List of the connections between audio components; each entry is a pair of strings, the first being the @@ -61,6 +61,7 @@ properties: For Odroid X2: "Headphone Jack", "Mic Jack", "DMIC" For Odroid U3, XU3: "Headphone Jack", "Speakers" For Odroid XU4: no entries + Deprecated, use audio-routing. samsung,audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array @@ -70,18 +71,17 @@ properties: required: - compatible - - model - cpu - codec -additionalProperties: false +unevaluatedProperties: false examples: - | sound { compatible = "hardkernel,odroid-xu3-audio"; model = "Odroid-XU3"; - samsung,audio-routing = + audio-routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "IN1", "Mic Jack", -- cgit v1.2.3 From 631e9d4b1f3241008bc6f1c62ec0d19d745d02be Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:54 +0200 Subject: ASoC: dt-bindings: samsung,tm2: use common sound card Reference the common sound card properties and deprecate the custom "samsung,audio-routing" in favor of generic one. This allows to remove "model" property and make the binding closer to other sounds cards. Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-6-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/samsung,tm2.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml index 491e08019c04..760592599143 100644 --- a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml @@ -10,6 +10,9 @@ maintainers: - Krzysztof Kozlowski - Sylwester Nawrocki +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: samsung,tm2-audio @@ -32,6 +35,8 @@ properties: being the connection's source; valid names for sources and sinks are the WM5110's and MAX98504's pins and the jacks on the board: HP, SPK, Main Mic, Sub Mic, Third Mic, Headset Mic. + Deprecated, use audio-routing. + deprecated: true $ref: /schemas/types.yaml#/definitions/non-unique-string-array i2s-controller: @@ -44,20 +49,15 @@ properties: mic-bias-gpios: description: GPIO pin that enables the Main Mic bias regulator. - model: - description: The user-visible name of this sound complex. - $ref: /schemas/types.yaml#/definitions/string - required: - compatible - audio-amplifier - audio-codec - - samsung,audio-routing + - audio-routing - i2s-controller - mic-bias-gpios - - model -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -70,7 +70,7 @@ examples: audio-amplifier = <&max98504>; mic-bias-gpios = <&gpr3 2 GPIO_ACTIVE_HIGH>; model = "wm5110"; - samsung,audio-routing = "HP", "HPOUT1L", + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", "SPK", "SPKOUT", "SPKOUT", "HPOUT2L", -- cgit v1.2.3 From ebba2fd5adc2d79afa10c00255a60c79665c091a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:55 +0200 Subject: ASoC: samsung: odroid: use of_property_present to check for property "samsung,audio-widgets" and "samsung,audio-routing" are not boolean properties, thus more appropriate is to use of_property_present() to check if they are present. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-7-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index a5442592bde4..1743bd55ba1a 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -223,14 +223,14 @@ static int odroid_audio_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { + if (of_property_present(dev->of_node, "samsung,audio-widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(card, "samsung,audio-widgets"); if (ret < 0) return ret; } - if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { + if (of_property_present(dev->of_node, "samsung,audio-routing")) { ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); if (ret < 0) -- cgit v1.2.3 From 55ebfafbc32db54259d91383faf65a5bc6bef382 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:56 +0200 Subject: ASoC: samsung: aries_wm8994: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-8-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 7492bb41456c..dd3cd2c9644a 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -620,10 +620,14 @@ static int aries_audio_probe(struct platform_device *pdev) /* Update card-name if provided through DT, else use default name */ snd_soc_of_parse_card_name(card, "model"); - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt; -- cgit v1.2.3 From c91e67145bc6d03f94416f7fbe566c6f6751cd47 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:57 +0200 Subject: ASoC: samsung: midas_wm1811: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-9-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 126098fdcf1b..2ec7e16ddfa2 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -476,10 +476,14 @@ static int midas_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } cpu = of_get_child_by_name(dev->of_node, "cpu"); -- cgit v1.2.3 From 2dc8c0366599cb4dfd939e6eafd94010f3aff233 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:58 +0200 Subject: ASoC: samsung: odroid: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-10-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 1743bd55ba1a..c93cb5a86426 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -230,12 +230,13 @@ static int odroid_audio_probe(struct platform_device *pdev) return ret; } - if (of_property_present(dev->of_node, "samsung,audio-routing")) { - ret = snd_soc_of_parse_audio_routing(card, - "samsung,audio-routing"); - if (ret < 0) - return ret; - } + ret = 0; + if (of_property_present(dev->of_node, "audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + else if (of_property_present(dev->of_node, "samsung,audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) + return ret; card->dai_link = odroid_card_dais; card->num_links = ARRAY_SIZE(odroid_card_dais); -- cgit v1.2.3 From 17b9f4387ebabb19b871bbe2d06562e48e4e7130 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:59 +0200 Subject: ASoC: samsung: tm2_wm5110: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-11-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/tm2_wm5110.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index d611ec9e5325..5ebf17f3de1e 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing is not specified or invalid\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing is not specified or invalid\n"); + return ret; + } } card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, -- cgit v1.2.3 From 12a95123bfe1dd1a6020a35f5e67a560591bb02a Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 4 Aug 2023 11:45:57 +0100 Subject: soundwire: bus: Allow SoundWire peripherals to register IRQ handlers Currently the in-band alerts for SoundWire peripherals can only be communicated to the driver through the interrupt_callback function. This however is slightly inconvenient for devices that wish to share IRQ handling code between SoundWire and I2C/SPI, the later would normally register an IRQ handler with the IRQ subsystem. However there is no reason the SoundWire in-band IRQs can not also be communicated as an actual IRQ to the driver. Add support for SoundWire peripherals to register a normal IRQ handler to receive SoundWire in-band alerts, allowing code to be shared across control buses. Note that we allow users to use both the interrupt_callback and the IRQ handler, this is useful for devices which must clear additional chip specific SoundWire registers that are not a part of the normal IRQ flow, or the SoundWire specification. Signed-off-by: Lucas Tanure Reviewed-by: Pierre-Louis Bossart Acked-by: Bard Liao Acked-by: Vinod Koul Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-2-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones --- drivers/soundwire/bus.c | 32 ++++++++++++++++++++++++++++++++ drivers/soundwire/bus_type.c | 12 ++++++++++++ include/linux/soundwire/sdw.h | 9 +++++++++ 3 files changed, 53 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index dba920ec88f6..cf55386256f3 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,23 @@ static int sdw_get_id(struct sdw_bus *bus) return 0; } +static int sdw_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct sdw_bus *bus = h->host_data; + + irq_set_chip_data(virq, bus); + irq_set_chip(virq, &bus->irq_chip); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops sdw_domain_ops = { + .map = sdw_irq_map, +}; + /** * sdw_bus_master_add() - add a bus Master instance * @bus: bus instance @@ -151,6 +169,14 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, bus->params.curr_bank = SDW_BANK0; bus->params.next_bank = SDW_BANK1; + bus->irq_chip.name = dev_name(bus->dev); + bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES, + &sdw_domain_ops, bus); + if (!bus->domain) { + dev_err(bus->dev, "Failed to add IRQ domain\n"); + return -EINVAL; + } + return 0; } EXPORT_SYMBOL(sdw_bus_master_add); @@ -187,6 +213,9 @@ static int sdw_delete_slave(struct device *dev, void *data) void sdw_bus_master_delete(struct sdw_bus *bus) { device_for_each_child(bus->dev, NULL, sdw_delete_slave); + + irq_domain_remove(bus->domain); + sdw_master_device_del(bus); sdw_bus_debugfs_exit(bus); @@ -1725,6 +1754,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) struct device *dev = &slave->dev; struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + if (slave->prop.use_domain_irq && slave->irq) + handle_nested_irq(slave->irq); + if (drv->ops && drv->ops->interrupt_callback) { slave_intr.sdca_cascade = sdca_cascade; slave_intr.control_port = clear; diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 1f43ee848eac..fafbc284e82d 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -122,6 +122,12 @@ static int sdw_drv_probe(struct device *dev) if (drv->ops && drv->ops->read_prop) drv->ops->read_prop(slave); + if (slave->prop.use_domain_irq) { + slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num); + if (!slave->irq) + dev_warn(dev, "Failed to map IRQ\n"); + } + /* init the sysfs as we have properties now */ ret = sdw_slave_sysfs_init(slave); if (ret < 0) @@ -166,7 +172,13 @@ static int sdw_drv_remove(struct device *dev) int ret = 0; mutex_lock(&slave->sdw_dev_lock); + slave->probed = false; + + if (slave->prop.use_domain_irq) + irq_dispose_mapping(irq_find_mapping(slave->bus->domain, + slave->dev_num)); + mutex_unlock(&slave->sdw_dev_lock); if (drv->remove) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f523ceabd059..8923387a7405 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include @@ -370,6 +372,7 @@ struct sdw_dpn_prop { * @clock_reg_supported: the Peripheral implements the clock base and scale * registers introduced with the SoundWire 1.2 specification. SDCA devices * do not need to set this boolean property as the registers are required. + * @use_domain_irq: call actual IRQ handler on slave, as well as callback */ struct sdw_slave_prop { u32 mipi_revision; @@ -394,6 +397,7 @@ struct sdw_slave_prop { u8 scp_int1_mask; u32 quirks; bool clock_reg_supported; + bool use_domain_irq; }; #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) @@ -641,6 +645,7 @@ struct sdw_slave_ops { * struct sdw_slave - SoundWire Slave * @id: MIPI device ID * @dev: Linux device + * @irq: IRQ number * @status: Status reported by the Slave * @bus: Bus handle * @prop: Slave properties @@ -670,6 +675,7 @@ struct sdw_slave_ops { struct sdw_slave { struct sdw_slave_id id; struct device dev; + int irq; enum sdw_slave_status status; struct sdw_bus *bus; struct sdw_slave_prop prop; @@ -885,6 +891,7 @@ struct sdw_master_ops { * is used to compute and program bus bandwidth, clock, frame shape, * transport and port parameters * @debugfs: Bus debugfs + * @domain: IRQ domain * @defer_msg: Defer message * @clk_stop_timeout: Clock stop timeout computed * @bank_switch_timeout: Bank switch timeout computed @@ -920,6 +927,8 @@ struct sdw_bus { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; #endif + struct irq_chip irq_chip; + struct irq_domain *domain; struct sdw_defer defer_msg; unsigned int clk_stop_timeout; u32 bank_switch_timeout; -- cgit v1.2.3 From ec77cad8d55c0fb39c0b17a682f78df4b92373a5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Aug 2023 11:45:58 +0100 Subject: dt-bindings: mfd: cirrus,cs42l43: Add initial DT binding The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed for portable applications. It provides a high dynamic range, stereo DAC for headphone output, two integrated Class D amplifiers for loudspeakers, and two ADCs for wired headset microphone input or stereo line input. PDM inputs are provided for digital microphones. Add a YAML DT binding document for this device. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-3-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones --- .../devicetree/bindings/sound/cirrus,cs42l43.yaml | 313 +++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml new file mode 100644 index 000000000000..7a6de938b11d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml @@ -0,0 +1,313 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs42l43.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS42L43 Audio CODEC + +maintainers: + - patches@opensource.cirrus.com + +description: | + The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface + (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed + for portable applications. It provides a high dynamic range, stereo + DAC for headphone output, two integrated Class D amplifiers for + loudspeakers, and two ADCs for wired headset microphone input or + stereo line input. PDM inputs are provided for digital microphones. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - cirrus,cs42l43 + + reg: + maxItems: 1 + + vdd-p-supply: + description: + Power supply for the high voltage interface. + + vdd-a-supply: + description: + Power supply for internal analog circuits. + + vdd-d-supply: + description: + Power supply for internal digital circuits. Can be internally supplied. + + vdd-io-supply: + description: + Power supply for external interface and internal digital logic. + + vdd-cp-supply: + description: + Power supply for the amplifier 3 and 4 charge pump. + + vdd-amp-supply: + description: + Power supply for amplifier 1 and 2. + + reset-gpios: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 + + "#sound-dai-cells": + const: 1 + + clocks: + items: + - description: Synchronous audio clock provided on mclk_in. + + clock-names: + const: mclk + + cirrus,bias-low: + type: boolean + description: + Select a 1.8V headset micbias rather than 2.8V. + + cirrus,bias-sense-microamp: + description: + Current at which the headset micbias sense clamp will engage, 0 to + disable. + enum: [ 0, 14, 23, 41, 50, 60, 68, 86, 95 ] + default: 0 + + cirrus,bias-ramp-ms: + description: + Time in milliseconds the hardware allows for the headset micbias to + ramp up. + enum: [ 10, 40, 90, 170 ] + default: 170 + + cirrus,detect-us: + description: + Time in microseconds the type detection will run for. Long values will + cause more audible effects, but give more accurate detection. + enum: [ 20, 100, 1000, 10000, 50000, 75000, 100000, 200000 ] + default: 10000 + + cirrus,button-automute: + type: boolean + description: + Enable the hardware automuting of decimator 1 when a headset button is + pressed. + + cirrus,buttons-ohms: + description: + Impedance in Ohms for each headset button, these should be listed in + ascending order. + minItems: 1 + maxItems: 6 + + cirrus,tip-debounce-ms: + description: + Software debounce on tip sense triggering in milliseconds. + default: 0 + + cirrus,tip-invert: + type: boolean + description: + Indicates tip detect polarity, inverted implies open-circuit whilst the + jack is inserted. + + cirrus,tip-disable-pullup: + type: boolean + description: + Indicates if the internal pullup on the tip detect should be disabled. + + cirrus,tip-fall-db-ms: + description: + Time in milliseconds a falling edge on the tip detect should be hardware + debounced for. Note the falling edge is considered after the invert. + enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ] + default: 500 + + cirrus,tip-rise-db-ms: + description: + Time in milliseconds a rising edge on the tip detect should be hardware + debounced for. Note the rising edge is considered after the invert. + enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ] + default: 500 + + cirrus,use-ring-sense: + type: boolean + description: + Indicates if the ring sense should be used. + + cirrus,ring-invert: + type: boolean + description: + Indicates ring detect polarity, inverted implies open-circuit whilst the + jack is inserted. + + cirrus,ring-disable-pullup: + type: boolean + description: + Indicates if the internal pullup on the ring detect should be disabled. + + cirrus,ring-fall-db-ms: + description: + Time in milliseconds a falling edge on the ring detect should be hardware + debounced for. Note the falling edge is considered after the invert. + enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ] + default: 500 + + cirrus,ring-rise-db-ms: + description: + Time in milliseconds a rising edge on the ring detect should be hardware + debounced for. Note the rising edge is considered after the invert. + enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ] + default: 500 + + pinctrl: + type: object + $ref: /schemas/pinctrl/pinctrl.yaml# + additionalProperties: false + + properties: + gpio-controller: true + + "#gpio-cells": + const: 2 + + gpio-ranges: + items: + - description: A phandle to the CODEC pinctrl node + minimum: 0 + - const: 0 + - const: 0 + - const: 3 + + patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/cirrus-cs42l43-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/cirrus-cs42l43-state" + additionalProperties: false + + spi: + type: object + $ref: /schemas/spi/spi-controller.yaml# + unevaluatedProperties: false + +$defs: + cirrus-cs42l43-state: + type: object + + allOf: + - $ref: /schemas/pinctrl/pincfg-node.yaml# + - $ref: /schemas/pinctrl/pinmux-node.yaml# + + oneOf: + - required: [ groups ] + - required: [ pins ] + + additionalProperties: false + + properties: + groups: + enum: [ gpio1, gpio2, gpio3, asp, pdmout2, pdmout1, i2c, spi ] + + pins: + enum: [ gpio1, gpio2, gpio3, + asp_dout, asp_fsync, asp_bclk, + pdmout2_clk, pdmout2_data, pdmout1_clk, pdmout1_data, + i2c_sda, i2c_scl, + spi_miso, spi_sck, spi_ssb ] + + function: + enum: [ gpio, spdif, irq, mic-shutter, spk-shutter ] + + drive-strength: + description: Set drive strength in mA + enum: [ 1, 2, 4, 8, 9, 10, 12, 16 ] + + input-debounce: + description: Set input debounce in uS + enum: [ 0, 85 ] + +required: + - compatible + - reg + - vdd-p-supply + - vdd-a-supply + - vdd-io-supply + - vdd-cp-supply + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cs42l43: codec@1a { + compatible = "cirrus,cs42l43"; + reg = <0x1a>; + + vdd-p-supply = <&vdd5v0>; + vdd-a-supply = <&vdd1v8>; + vdd-io-supply = <&vdd1v8>; + vdd-cp-supply = <&vdd1v8>; + vdd-amp-supply = <&vdd5v0>; + + reset-gpios = <&gpio 0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio>; + interrupts = <56 IRQ_TYPE_LEVEL_LOW>; + + #sound-dai-cells = <1>; + + clocks = <&clks 0>; + clock-names = "mclk"; + + cs42l43_pins: pinctrl { + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&cs42l43_pins 0 0 3>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinsettings>; + + pinsettings: default-state { + shutter-pins { + groups = "gpio3"; + function = "mic-shutter"; + }; + }; + }; + + spi { + #address-cells = <1>; + #size-cells = <0>; + + cs-gpios = <&cs42l43_pins 1 0>; + + sensor@0 { + compatible = "bosch,bme680"; + reg = <0>; + spi-max-frequency = <1400000>; + }; + }; + }; + }; -- cgit v1.2.3 From ace6d14481386ec6c1b63cc2b24c71433a583dc2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Aug 2023 11:45:59 +0100 Subject: mfd: cs42l43: Add support for cs42l43 core driver The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed for portable applications. It provides a high dynamic range, stereo DAC for headphone output, two integrated Class D amplifiers for loudspeakers, and two ADCs for wired headset microphone input or stereo line input. PDM inputs are provided for digital microphones. The MFD component registers and initialises the device and provides PM/system power management. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-4-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones --- MAINTAINERS | 2 + drivers/mfd/Kconfig | 23 + drivers/mfd/Makefile | 3 + drivers/mfd/cs42l43-i2c.c | 98 ++++ drivers/mfd/cs42l43-sdw.c | 239 ++++++++ drivers/mfd/cs42l43.c | 1188 ++++++++++++++++++++++++++++++++++++++ drivers/mfd/cs42l43.h | 28 + include/linux/mfd/cs42l43-regs.h | 1184 +++++++++++++++++++++++++++++++++++++ include/linux/mfd/cs42l43.h | 102 ++++ 9 files changed, 2867 insertions(+) create mode 100644 drivers/mfd/cs42l43-i2c.c create mode 100644 drivers/mfd/cs42l43-sdw.c create mode 100644 drivers/mfd/cs42l43.c create mode 100644 drivers/mfd/cs42l43.h create mode 100644 include/linux/mfd/cs42l43-regs.h create mode 100644 include/linux/mfd/cs42l43.h diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc..45aa18c45d20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4879,7 +4879,9 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: patches@opensource.cirrus.com S: Maintained F: Documentation/devicetree/bindings/sound/cirrus,cs* +F: drivers/mfd/cs42l43* F: include/dt-bindings/sound/cs* +F: include/linux/mfd/cs42l43* F: include/sound/cs* F: sound/pci/hda/cs* F: sound/pci/hda/hda_cs_dsp_ctl.* diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6f5b259a6d6a..85be64579fc9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -237,6 +237,29 @@ config MFD_CROS_EC_DEV To compile this driver as a module, choose M here: the module will be called cros-ec-dev. +config MFD_CS42L43 + tristate + select MFD_CORE + select REGMAP + +config MFD_CS42L43_I2C + tristate "Cirrus Logic CS42L43 (I2C)" + depends on I2C + select REGMAP_I2C + select MFD_CS42L43 + help + Select this to support the Cirrus Logic CS42L43 PC CODEC with + headphone and class D speaker drivers over I2C. + +config MFD_CS42L43_SDW + tristate "Cirrus Logic CS42L43 (SoundWire)" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select MFD_CS42L43 + help + Select this to support the Cirrus Logic CS42L43 PC CODEC with + headphone and class D speaker drivers over SoundWire. + config MFD_MADERA tristate "Cirrus Logic Madera codecs" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f3d1f1dc73b5..c66f07edcd0e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,6 +13,9 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o +obj-$(CONFIG_MFD_CS42L43) += cs42l43.o +obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o +obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c new file mode 100644 index 000000000000..4922211680c9 --- /dev/null +++ b/drivers/mfd/cs42l43-i2c.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS42L43 I2C driver + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +static const struct regmap_config cs42l43_i2c_regmap = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = CS42L43_MCU_RAM_MAX, + .readable_reg = cs42l43_readable_register, + .volatile_reg = cs42l43_volatile_register, + .precious_reg = cs42l43_precious_register, + + .cache_type = REGCACHE_MAPLE, + .reg_defaults = cs42l43_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default), +}; + +static int cs42l43_i2c_probe(struct i2c_client *i2c) +{ + struct cs42l43 *cs42l43; + int ret; + + cs42l43 = devm_kzalloc(&i2c->dev, sizeof(*cs42l43), GFP_KERNEL); + if (!cs42l43) + return -ENOMEM; + + cs42l43->dev = &i2c->dev; + cs42l43->irq = i2c->irq; + /* A device on an I2C is always attached by definition. */ + cs42l43->attached = true; + + cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap); + if (IS_ERR(cs42l43->regmap)) { + ret = PTR_ERR(cs42l43->regmap); + dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + return cs42l43_dev_probe(cs42l43); +} + +static void cs42l43_i2c_remove(struct i2c_client *i2c) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev); + + cs42l43_dev_remove(cs42l43); +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id cs42l43_of_match[] = { + { .compatible = "cirrus,cs42l43", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l43_of_match); +#endif + +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id cs42l43_acpi_match[] = { + { "CSC4243", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match); +#endif + +static struct i2c_driver cs42l43_i2c_driver = { + .driver = { + .name = "cs42l43", + .pm = pm_ptr(&cs42l43_pm_ops), + .of_match_table = of_match_ptr(cs42l43_of_match), + .acpi_match_table = ACPI_PTR(cs42l43_acpi_match), + }, + + .probe = cs42l43_i2c_probe, + .remove = cs42l43_i2c_remove, +}; +module_i2c_driver(cs42l43_i2c_driver); + +MODULE_IMPORT_NS(MFD_CS42L43); + +MODULE_DESCRIPTION("CS42L43 I2C Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c new file mode 100644 index 000000000000..7392b3d2e6b9 --- /dev/null +++ b/drivers/mfd/cs42l43-sdw.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS42L43 SoundWire driver + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +enum cs42l43_sdw_ports { + CS42L43_DMIC_DEC_ASP_PORT = 1, + CS42L43_SPK_TX_PORT, + CS42L43_SPDIF_HP_PORT, + CS42L43_SPK_RX_PORT, + CS42L43_ASP_PORT, +}; + +static const struct regmap_config cs42l43_sdw_regmap = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + + .max_register = CS42L43_MCU_RAM_MAX, + .readable_reg = cs42l43_readable_register, + .volatile_reg = cs42l43_volatile_register, + .precious_reg = cs42l43_precious_register, + + .cache_type = REGCACHE_MAPLE, + .reg_defaults = cs42l43_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default), +}; + +static int cs42l43_read_prop(struct sdw_slave *sdw) +{ + struct sdw_slave_prop *prop = &sdw->prop; + struct device *dev = &sdw->dev; + struct sdw_dpn_prop *dpn; + unsigned long addr; + int nval; + int i; + u32 bit; + + prop->use_domain_irq = true; + prop->paging_support = true; + prop->wake_capable = true; + prop->source_ports = BIT(CS42L43_DMIC_DEC_ASP_PORT) | BIT(CS42L43_SPK_TX_PORT); + prop->sink_ports = BIT(CS42L43_SPDIF_HP_PORT) | + BIT(CS42L43_SPK_RX_PORT) | BIT(CS42L43_ASP_PORT); + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | + SDW_SCP_INT1_IMPL_DEF; + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].max_ch = 2; + dpn[i].type = SDW_DPN_FULL; + dpn[i].max_word = 24; + i++; + } + /* + * All ports are 2 channels max, except the first one, + * CS42L43_DMIC_DEC_ASP_PORT. + */ + dpn[CS42L43_DMIC_DEC_ASP_PORT].max_ch = 4; + + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].max_ch = 2; + dpn[i].type = SDW_DPN_FULL; + dpn[i].max_word = 24; + i++; + } + + return 0; +} + +static int cs42l43_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); + + switch (status) { + case SDW_SLAVE_ATTACHED: + dev_dbg(cs42l43->dev, "Device attach\n"); + + sdw_write_no_pm(sdw, CS42L43_GEN_INT_MASK_1, + CS42L43_INT_STAT_GEN1_MASK); + + cs42l43->attached = true; + + complete(&cs42l43->device_attach); + break; + case SDW_SLAVE_UNATTACHED: + dev_dbg(cs42l43->dev, "Device detach\n"); + + cs42l43->attached = false; + + reinit_completion(&cs42l43->device_attach); + complete(&cs42l43->device_detach); + break; + default: + break; + } + + return 0; +} + +static int cs42l43_sdw_interrupt(struct sdw_slave *sdw, + struct sdw_slave_intr_status *status) +{ + /* + * The IRQ itself was handled through the regmap_irq handler, this is + * just clearing up the additional Cirrus SoundWire registers that are + * not covered by the SoundWire framework or the IRQ handler itself. + * There is only a single bit in GEN_INT_STAT_1 and it doesn't clear if + * IRQs are still pending so doing a read/write here after handling the + * IRQ is fine. + */ + sdw_read_no_pm(sdw, CS42L43_GEN_INT_STAT_1); + sdw_write_no_pm(sdw, CS42L43_GEN_INT_STAT_1, CS42L43_INT_STAT_GEN1_MASK); + + return 0; +} + +static int cs42l43_sdw_bus_config(struct sdw_slave *sdw, + struct sdw_bus_params *params) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); + int ret = 0; + + mutex_lock(&cs42l43->pll_lock); + + if (cs42l43->sdw_freq != params->curr_dr_freq / 2) { + if (cs42l43->sdw_pll_active) { + dev_err(cs42l43->dev, + "PLL active can't change SoundWire bus clock\n"); + ret = -EBUSY; + } else { + cs42l43->sdw_freq = params->curr_dr_freq / 2; + } + } + + mutex_unlock(&cs42l43->pll_lock); + + return ret; +} + +static const struct sdw_slave_ops cs42l43_sdw_ops = { + .read_prop = cs42l43_read_prop, + .update_status = cs42l43_sdw_update_status, + .interrupt_callback = cs42l43_sdw_interrupt, + .bus_config = cs42l43_sdw_bus_config, +}; + +static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) +{ + struct cs42l43 *cs42l43; + struct device *dev = &sdw->dev; + int ret; + + cs42l43 = devm_kzalloc(dev, sizeof(*cs42l43), GFP_KERNEL); + if (!cs42l43) + return -ENOMEM; + + cs42l43->dev = dev; + cs42l43->sdw = sdw; + + cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap); + if (IS_ERR(cs42l43->regmap)) { + ret = PTR_ERR(cs42l43->regmap); + dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + return cs42l43_dev_probe(cs42l43); +} + +static int cs42l43_sdw_remove(struct sdw_slave *sdw) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); + + cs42l43_dev_remove(cs42l43); + + return 0; +} + +static const struct sdw_device_id cs42l43_sdw_id[] = { + SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0), + {} +}; +MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id); + +static struct sdw_driver cs42l43_sdw_driver = { + .driver = { + .name = "cs42l43", + .pm = pm_ptr(&cs42l43_pm_ops), + }, + + .probe = cs42l43_sdw_probe, + .remove = cs42l43_sdw_remove, + .id_table = cs42l43_sdw_id, + .ops = &cs42l43_sdw_ops, +}; +module_sdw_driver(cs42l43_sdw_driver); + +MODULE_IMPORT_NS(MFD_CS42L43); + +MODULE_DESCRIPTION("CS42L43 SoundWire Driver"); +MODULE_AUTHOR("Lucas Tanure "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c new file mode 100644 index 000000000000..37b23e9bae82 --- /dev/null +++ b/drivers/mfd/cs42l43.c @@ -0,0 +1,1188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS42L43 core driver + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +#define CS42L43_RESET_DELAY 20 + +#define CS42L43_SDW_ATTACH_TIMEOUT 500 +#define CS42L43_SDW_DETACH_TIMEOUT 100 + +#define CS42L43_MCU_BOOT_STAGE1 1 +#define CS42L43_MCU_BOOT_STAGE2 2 +#define CS42L43_MCU_BOOT_STAGE3 3 +#define CS42L43_MCU_BOOT_STAGE4 4 +#define CS42L43_MCU_POLL 5000 +#define CS42L43_MCU_CMD_TIMEOUT 20000 +#define CS42L43_MCU_UPDATE_FORMAT 3 +#define CS42L43_MCU_UPDATE_OFFSET 0x100000 +#define CS42L43_MCU_UPDATE_TIMEOUT 500000 +#define CS42L43_MCU_UPDATE_RETRIES 5 + +#define CS42L43_MCU_SUPPORTED_REV 0x2105 +#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200 +#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001 + +#define CS42L43_VDDP_DELAY 50 +#define CS42L43_VDDD_DELAY 1000 + +#define CS42L43_AUTOSUSPEND_TIME 250 + +struct cs42l43_patch_header { + __le16 version; + __le16 size; + u8 reserved; + u8 secure; + __le16 bss_size; + __le32 apply_addr; + __le32 checksum; + __le32 sha; + __le16 swrev; + __le16 patchid; + __le16 ipxid; + __le16 romver; + __le32 load_addr; +} __packed; + +static const struct reg_sequence cs42l43_reva_patch[] = { + { 0x4000, 0x00000055 }, + { 0x4000, 0x000000AA }, + { 0x10084, 0x00000000 }, + { 0x1741C, 0x00CD2000 }, + { 0x1718C, 0x00000003 }, + { 0x4000, 0x00000000 }, + { CS42L43_CCM_BLK_CLK_CONTROL, 0x00000002 }, + { CS42L43_HPPATHVOL, 0x011B011B }, + { CS42L43_OSC_DIV_SEL, 0x00000001 }, + { CS42L43_DACCNFG2, 0x00000005 }, + { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 }, + { CS42L43_RELID, 0x0000000F }, +}; + +const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { + { CS42L43_DRV_CTRL1, 0x000186C0 }, + { CS42L43_DRV_CTRL3, 0x286DB018 }, + { CS42L43_DRV_CTRL4, 0x000006D8 }, + { CS42L43_DRV_CTRL_5, 0x136C00C0 }, + { CS42L43_GPIO_CTRL1, 0x00000707 }, + { CS42L43_GPIO_CTRL2, 0x00000000 }, + { CS42L43_GPIO_FN_SEL, 0x00000000 }, + { CS42L43_MCLK_SRC_SEL, 0x00000000 }, + { CS42L43_SAMPLE_RATE1, 0x00000003 }, + { CS42L43_SAMPLE_RATE2, 0x00000003 }, + { CS42L43_SAMPLE_RATE3, 0x00000003 }, + { CS42L43_SAMPLE_RATE4, 0x00000003 }, + { CS42L43_PLL_CONTROL, 0x00000000 }, + { CS42L43_FS_SELECT1, 0x00000000 }, + { CS42L43_FS_SELECT2, 0x00000000 }, + { CS42L43_FS_SELECT3, 0x00000000 }, + { CS42L43_FS_SELECT4, 0x00000000 }, + { CS42L43_PDM_CONTROL, 0x00000000 }, + { CS42L43_ASP_CLK_CONFIG1, 0x00010001 }, + { CS42L43_ASP_CLK_CONFIG2, 0x00000000 }, + { CS42L43_OSC_DIV_SEL, 0x00000001 }, + { CS42L43_ADC_B_CTRL1, 0x00000000 }, + { CS42L43_ADC_B_CTRL2, 0x00000000 }, + { CS42L43_DECIM_HPF_WNF_CTRL1, 0x00000001 }, + { CS42L43_DECIM_HPF_WNF_CTRL2, 0x00000001 }, + { CS42L43_DECIM_HPF_WNF_CTRL3, 0x00000001 }, + { CS42L43_DECIM_HPF_WNF_CTRL4, 0x00000001 }, + { CS42L43_DMIC_PDM_CTRL, 0x00000000 }, + { CS42L43_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 }, + { CS42L43_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 }, + { CS42L43_INTP_VOLUME_CTRL1, 0x00000180 }, + { CS42L43_INTP_VOLUME_CTRL2, 0x00000180 }, + { CS42L43_AMP1_2_VOL_RAMP, 0x00000022 }, + { CS42L43_ASP_CTRL, 0x00000004 }, + { CS42L43_ASP_FSYNC_CTRL1, 0x000000FA }, + { CS42L43_ASP_FSYNC_CTRL2, 0x00000001 }, + { CS42L43_ASP_FSYNC_CTRL3, 0x00000000 }, + { CS42L43_ASP_FSYNC_CTRL4, 0x000001F4 }, + { CS42L43_ASP_DATA_CTRL, 0x0000003A }, + { CS42L43_ASP_RX_EN, 0x00000000 }, + { CS42L43_ASP_TX_EN, 0x00000000 }, + { CS42L43_ASP_RX_CH1_CTRL, 0x00170001 }, + { CS42L43_ASP_RX_CH2_CTRL, 0x00170031 }, + { CS42L43_ASP_RX_CH3_CTRL, 0x00170061 }, + { CS42L43_ASP_RX_CH4_CTRL, 0x00170091 }, + { CS42L43_ASP_RX_CH5_CTRL, 0x001700C1 }, + { CS42L43_ASP_RX_CH6_CTRL, 0x001700F1 }, + { CS42L43_ASP_TX_CH1_CTRL, 0x00170001 }, + { CS42L43_ASP_TX_CH2_CTRL, 0x00170031 }, + { CS42L43_ASP_TX_CH3_CTRL, 0x00170061 }, + { CS42L43_ASP_TX_CH4_CTRL, 0x00170091 }, + { CS42L43_ASP_TX_CH5_CTRL, 0x001700C1 }, + { CS42L43_ASP_TX_CH6_CTRL, 0x001700F1 }, + { CS42L43_ASPTX1_INPUT, 0x00800000 }, + { CS42L43_ASPTX2_INPUT, 0x00800000 }, + { CS42L43_ASPTX3_INPUT, 0x00800000 }, + { CS42L43_ASPTX4_INPUT, 0x00800000 }, + { CS42L43_ASPTX5_INPUT, 0x00800000 }, + { CS42L43_ASPTX6_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00800000 }, + { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00800000 }, + { CS42L43_ASRC_INT1_INPUT1, 0x00800000 }, + { CS42L43_ASRC_INT2_INPUT1, 0x00800000 }, + { CS42L43_ASRC_INT3_INPUT1, 0x00800000 }, + { CS42L43_ASRC_INT4_INPUT1, 0x00800000 }, + { CS42L43_ASRC_DEC1_INPUT1, 0x00800000 }, + { CS42L43_ASRC_DEC2_INPUT1, 0x00800000 }, + { CS42L43_ASRC_DEC3_INPUT1, 0x00800000 }, + { CS42L43_ASRC_DEC4_INPUT1, 0x00800000 }, + { CS42L43_ISRC1INT1_INPUT1, 0x00800000 }, + { CS42L43_ISRC1INT2_INPUT1, 0x00800000 }, + { CS42L43_ISRC1DEC1_INPUT1, 0x00800000 }, + { CS42L43_ISRC1DEC2_INPUT1, 0x00800000 }, + { CS42L43_ISRC2INT1_INPUT1, 0x00800000 }, + { CS42L43_ISRC2INT2_INPUT1, 0x00800000 }, + { CS42L43_ISRC2DEC1_INPUT1, 0x00800000 }, + { CS42L43_ISRC2DEC2_INPUT1, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT1, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT2, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT3, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT4, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT1, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT2, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT3, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT4, 0x00800000 }, + { CS42L43_SPDIF1_INPUT1, 0x00800000 }, + { CS42L43_SPDIF2_INPUT1, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT1, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT2, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT3, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT4, 0x00800000 }, + { CS42L43_AMP2MIX_INPUT1, 0x00800000 }, + { CS42L43_AMP2MIX_INPUT2, 0x00800000 }, + { CS42L43_AMP2MIX_INPUT3, 0x00800000 }, + { CS42L43_AMP2MIX_INPUT4, 0x00800000 }, + { CS42L43_AMP3MIX_INPUT1, 0x00800000 }, + { CS42L43_AMP3MIX_INPUT2, 0x00800000 }, + { CS42L43_AMP3MIX_INPUT3, 0x00800000 }, + { CS42L43_AMP3MIX_INPUT4, 0x00800000 }, + { CS42L43_AMP4MIX_INPUT1, 0x00800000 }, + { CS42L43_AMP4MIX_INPUT2, 0x00800000 }, + { CS42L43_AMP4MIX_INPUT3, 0x00800000 }, + { CS42L43_AMP4MIX_INPUT4, 0x00800000 }, + { CS42L43_ASRC_INT_ENABLES, 0x00000100 }, + { CS42L43_ASRC_DEC_ENABLES, 0x00000100 }, + { CS42L43_PDNCNTL, 0x00000000 }, + { CS42L43_RINGSENSE_DEB_CTRL, 0x0000001B }, + { CS42L43_TIPSENSE_DEB_CTRL, 0x0000001B }, + { CS42L43_HS2, 0x050106F3 }, + { CS42L43_STEREO_MIC_CTRL, 0x00000000 }, + { CS42L43_STEREO_MIC_CLAMP_CTRL, 0x00000001 }, + { CS42L43_BLOCK_EN2, 0x00000000 }, + { CS42L43_BLOCK_EN3, 0x00000000 }, + { CS42L43_BLOCK_EN4, 0x00000000 }, + { CS42L43_BLOCK_EN5, 0x00000000 }, + { CS42L43_BLOCK_EN6, 0x00000000 }, + { CS42L43_BLOCK_EN7, 0x00000000 }, + { CS42L43_BLOCK_EN8, 0x00000000 }, + { CS42L43_BLOCK_EN9, 0x00000000 }, + { CS42L43_BLOCK_EN10, 0x00000000 }, + { CS42L43_BLOCK_EN11, 0x00000000 }, + { CS42L43_TONE_CH1_CTRL, 0x00000000 }, + { CS42L43_TONE_CH2_CTRL, 0x00000000 }, + { CS42L43_MIC_DETECT_CONTROL_1, 0x00000003 }, + { CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, 0x02000003 }, + { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 }, + { CS42L43_ISRC1_CTRL, 0x00000000 }, + { CS42L43_ISRC2_CTRL, 0x00000000 }, + { CS42L43_CTRL_REG, 0x00000006 }, + { CS42L43_FDIV_FRAC, 0x40000000 }, + { CS42L43_CAL_RATIO, 0x00000080 }, + { CS42L43_SPI_CLK_CONFIG1, 0x00000000 }, + { CS42L43_SPI_CONFIG1, 0x00000000 }, + { CS42L43_SPI_CONFIG2, 0x00000000 }, + { CS42L43_SPI_CONFIG3, 0x00000001 }, + { CS42L43_SPI_CONFIG4, 0x00000000 }, + { CS42L43_TRAN_CONFIG3, 0x00000000 }, + { CS42L43_TRAN_CONFIG4, 0x00000000 }, + { CS42L43_TRAN_CONFIG5, 0x00000000 }, + { CS42L43_TRAN_CONFIG6, 0x00000000 }, + { CS42L43_TRAN_CONFIG7, 0x00000000 }, + { CS42L43_TRAN_CONFIG8, 0x00000000 }, + { CS42L43_DACCNFG1, 0x00000008 }, + { CS42L43_DACCNFG2, 0x00000005 }, + { CS42L43_HPPATHVOL, 0x011B011B }, + { CS42L43_PGAVOL, 0x00003470 }, + { CS42L43_LOADDETENA, 0x00000000 }, + { CS42L43_CTRL, 0x00000037 }, + { CS42L43_COEFF_DATA_IN0, 0x00000000 }, + { CS42L43_COEFF_RD_WR0, 0x00000000 }, + { CS42L43_START_EQZ0, 0x00000000 }, + { CS42L43_MUTE_EQ_IN0, 0x00000000 }, + { CS42L43_DECIM_MASK, 0x0000000F }, + { CS42L43_EQ_MIX_MASK, 0x0000000F }, + { CS42L43_ASP_MASK, 0x000000FF }, + { CS42L43_PLL_MASK, 0x00000003 }, + { CS42L43_SOFT_MASK, 0x0000FFFF }, + { CS42L43_SWIRE_MASK, 0x00007FFF }, + { CS42L43_MSM_MASK, 0x00000FFF }, + { CS42L43_ACC_DET_MASK, 0x00000FFF }, + { CS42L43_I2C_TGT_MASK, 0x00000003 }, + { CS42L43_SPI_MSTR_MASK, 0x00000007 }, + { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0x00000001 }, + { CS42L43_OTP_MASK, 0x00000007 }, + { CS42L43_CLASS_D_AMP_MASK, 0x00003FFF }, + { CS42L43_GPIO_INT_MASK, 0x0000003F }, + { CS42L43_ASRC_MASK, 0x0000000F }, + { CS42L43_HPOUT_MASK, 0x00000003 }, +}; +EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43); + +bool cs42l43_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L43_DEVID: + case CS42L43_REVID: + case CS42L43_RELID: + case CS42L43_SFT_RESET: + case CS42L43_DRV_CTRL1: + case CS42L43_DRV_CTRL3: + case CS42L43_DRV_CTRL4: + case CS42L43_DRV_CTRL_5: + case CS42L43_GPIO_CTRL1: + case CS42L43_GPIO_CTRL2: + case CS42L43_GPIO_STS: + case CS42L43_GPIO_FN_SEL: + case CS42L43_MCLK_SRC_SEL: + case CS42L43_SAMPLE_RATE1 ... CS42L43_SAMPLE_RATE4: + case CS42L43_PLL_CONTROL: + case CS42L43_FS_SELECT1 ... CS42L43_FS_SELECT4: + case CS42L43_PDM_CONTROL: + case CS42L43_ASP_CLK_CONFIG1 ... CS42L43_ASP_CLK_CONFIG2: + case CS42L43_OSC_DIV_SEL: + case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2: + case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4: + case CS42L43_DMIC_PDM_CTRL: + case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4: + case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2: + case CS42L43_AMP1_2_VOL_RAMP: + case CS42L43_ASP_CTRL: + case CS42L43_ASP_FSYNC_CTRL1 ... CS42L43_ASP_FSYNC_CTRL4: + case CS42L43_ASP_DATA_CTRL: + case CS42L43_ASP_RX_EN ... CS42L43_ASP_TX_EN: + case CS42L43_ASP_RX_CH1_CTRL ... CS42L43_ASP_RX_CH6_CTRL: + case CS42L43_ASP_TX_CH1_CTRL ... CS42L43_ASP_TX_CH6_CTRL: + case CS42L43_OTP_REVISION_ID: + case CS42L43_ASPTX1_INPUT: + case CS42L43_ASPTX2_INPUT: + case CS42L43_ASPTX3_INPUT: + case CS42L43_ASPTX4_INPUT: + case CS42L43_ASPTX5_INPUT: + case CS42L43_ASPTX6_INPUT: + case CS42L43_SWIRE_DP1_CH1_INPUT: + case CS42L43_SWIRE_DP1_CH2_INPUT: + case CS42L43_SWIRE_DP1_CH3_INPUT: + case CS42L43_SWIRE_DP1_CH4_INPUT: + case CS42L43_SWIRE_DP2_CH1_INPUT: + case CS42L43_SWIRE_DP2_CH2_INPUT: + case CS42L43_SWIRE_DP3_CH1_INPUT: + case CS42L43_SWIRE_DP3_CH2_INPUT: + case CS42L43_SWIRE_DP4_CH1_INPUT: + case CS42L43_SWIRE_DP4_CH2_INPUT: + case CS42L43_ASRC_INT1_INPUT1: + case CS42L43_ASRC_INT2_INPUT1: + case CS42L43_ASRC_INT3_INPUT1: + case CS42L43_ASRC_INT4_INPUT1: + case CS42L43_ASRC_DEC1_INPUT1: + case CS42L43_ASRC_DEC2_INPUT1: + case CS42L43_ASRC_DEC3_INPUT1: + case CS42L43_ASRC_DEC4_INPUT1: + case CS42L43_ISRC1INT1_INPUT1: + case CS42L43_ISRC1INT2_INPUT1: + case CS42L43_ISRC1DEC1_INPUT1: + case CS42L43_ISRC1DEC2_INPUT1: + case CS42L43_ISRC2INT1_INPUT1: + case CS42L43_ISRC2INT2_INPUT1: + case CS42L43_ISRC2DEC1_INPUT1: + case CS42L43_ISRC2DEC2_INPUT1: + case CS42L43_EQ1MIX_INPUT1 ... CS42L43_EQ1MIX_INPUT4: + case CS42L43_EQ2MIX_INPUT1 ... CS42L43_EQ2MIX_INPUT4: + case CS42L43_SPDIF1_INPUT1: + case CS42L43_SPDIF2_INPUT1: + case CS42L43_AMP1MIX_INPUT1 ... CS42L43_AMP1MIX_INPUT4: + case CS42L43_AMP2MIX_INPUT1 ... CS42L43_AMP2MIX_INPUT4: + case CS42L43_AMP3MIX_INPUT1 ... CS42L43_AMP3MIX_INPUT4: + case CS42L43_AMP4MIX_INPUT1 ... CS42L43_AMP4MIX_INPUT4: + case CS42L43_ASRC_INT_ENABLES ... CS42L43_ASRC_DEC_ENABLES: + case CS42L43_PDNCNTL: + case CS42L43_RINGSENSE_DEB_CTRL: + case CS42L43_TIPSENSE_DEB_CTRL: + case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: + case CS42L43_HS2: + case CS42L43_HS_STAT: + case CS42L43_MCU_SW_INTERRUPT: + case CS42L43_STEREO_MIC_CTRL: + case CS42L43_STEREO_MIC_CLAMP_CTRL: + case CS42L43_BLOCK_EN2 ... CS42L43_BLOCK_EN11: + case CS42L43_TONE_CH1_CTRL ... CS42L43_TONE_CH2_CTRL: + case CS42L43_MIC_DETECT_CONTROL_1: + case CS42L43_DETECT_STATUS_1: + case CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL: + case CS42L43_MIC_DETECT_CONTROL_ANDROID: + case CS42L43_ISRC1_CTRL: + case CS42L43_ISRC2_CTRL: + case CS42L43_CTRL_REG: + case CS42L43_FDIV_FRAC: + case CS42L43_CAL_RATIO: + case CS42L43_SPI_CLK_CONFIG1: + case CS42L43_SPI_CONFIG1 ... CS42L43_SPI_CONFIG4: + case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: + case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG8: + case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: + case CS42L43_TX_DATA: + case CS42L43_RX_DATA: + case CS42L43_DACCNFG1 ... CS42L43_DACCNFG2: + case CS42L43_HPPATHVOL: + case CS42L43_PGAVOL: + case CS42L43_LOADDETRESULTS: + case CS42L43_LOADDETENA: + case CS42L43_CTRL: + case CS42L43_COEFF_DATA_IN0: + case CS42L43_COEFF_RD_WR0: + case CS42L43_INIT_DONE0: + case CS42L43_START_EQZ0: + case CS42L43_MUTE_EQ_IN0: + case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: + case CS42L43_DECIM_MASK ... CS42L43_HPOUT_MASK: + case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: + case CS42L43_BOOT_CONTROL: + case CS42L43_BLOCK_EN: + case CS42L43_SHUTTER_CONTROL: + case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43); + +bool cs42l43_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L43_SFT_RESET: + case CS42L43_TX_DATA: + case CS42L43_RX_DATA: + case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: + case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43); + +bool cs42l43_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L43_DEVID: + case CS42L43_REVID: + case CS42L43_RELID: + case CS42L43_GPIO_STS: + case CS42L43_OTP_REVISION_ID: + case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: + case CS42L43_HS_STAT: + case CS42L43_MCU_SW_INTERRUPT: + case CS42L43_DETECT_STATUS_1: + case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: + case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG2: + case CS42L43_TRAN_CONFIG8: + case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: + case CS42L43_LOADDETRESULTS: + case CS42L43_INIT_DONE0: + case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: + case CS42L43_BOOT_CONTROL: + case CS42L43_BLOCK_EN: + return true; + default: + return cs42l43_precious_register(dev, reg); + } +} +EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43); + +#define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT) + +#define CS42L43_IRQ_REG(name, reg) REGMAP_IRQ_REG(CS42L43_##name, \ + CS42L43_IRQ_OFFSET(reg), \ + CS42L43_##name##_INT_MASK) + +static const struct regmap_irq cs42l43_regmap_irqs[] = { + CS42L43_IRQ_REG(PLL_LOST_LOCK, PLL), + CS42L43_IRQ_REG(PLL_READY, PLL), + + CS42L43_IRQ_REG(HP_STARTUP_DONE, MSM), + CS42L43_IRQ_REG(HP_SHUTDOWN_DONE, MSM), + CS42L43_IRQ_REG(HSDET_DONE, MSM), + CS42L43_IRQ_REG(TIPSENSE_UNPLUG_DB, MSM), + CS42L43_IRQ_REG(TIPSENSE_PLUG_DB, MSM), + CS42L43_IRQ_REG(RINGSENSE_UNPLUG_DB, MSM), + CS42L43_IRQ_REG(RINGSENSE_PLUG_DB, MSM), + CS42L43_IRQ_REG(TIPSENSE_UNPLUG_PDET, MSM), + CS42L43_IRQ_REG(TIPSENSE_PLUG_PDET, MSM), + CS42L43_IRQ_REG(RINGSENSE_UNPLUG_PDET, MSM), + CS42L43_IRQ_REG(RINGSENSE_PLUG_PDET, MSM), + + CS42L43_IRQ_REG(HS2_BIAS_SENSE, ACC_DET), + CS42L43_IRQ_REG(HS1_BIAS_SENSE, ACC_DET), + CS42L43_IRQ_REG(DC_DETECT1_FALSE, ACC_DET), + CS42L43_IRQ_REG(DC_DETECT1_TRUE, ACC_DET), + CS42L43_IRQ_REG(HSBIAS_CLAMPED, ACC_DET), + CS42L43_IRQ_REG(HS3_4_BIAS_SENSE, ACC_DET), + + CS42L43_IRQ_REG(AMP2_CLK_STOP_FAULT, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_CLK_STOP_FAULT, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_VDDSPK_FAULT, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_VDDSPK_FAULT, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_SHUTDOWN_DONE, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_SHUTDOWN_DONE, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_STARTUP_DONE, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_STARTUP_DONE, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_THERM_SHDN, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_THERM_SHDN, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_THERM_WARN, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_THERM_WARN, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP2_SCDET, CLASS_D_AMP), + CS42L43_IRQ_REG(AMP1_SCDET, CLASS_D_AMP), + + CS42L43_IRQ_REG(GPIO3_FALL, GPIO), + CS42L43_IRQ_REG(GPIO3_RISE, GPIO), + CS42L43_IRQ_REG(GPIO2_FALL, GPIO), + CS42L43_IRQ_REG(GPIO2_RISE, GPIO), + CS42L43_IRQ_REG(GPIO1_FALL, GPIO), + CS42L43_IRQ_REG(GPIO1_RISE, GPIO), + + CS42L43_IRQ_REG(HP_ILIMIT, HPOUT), + CS42L43_IRQ_REG(HP_LOADDET_DONE, HPOUT), +}; + +static const struct regmap_irq_chip cs42l43_irq_chip = { + .name = "cs42l43", + + .status_base = CS42L43_DECIM_INT, + .mask_base = CS42L43_DECIM_MASK, + .num_regs = 16, + + .irqs = cs42l43_regmap_irqs, + .num_irqs = ARRAY_SIZE(cs42l43_regmap_irqs), + + .runtime_pm = true, +}; + +static const char * const cs42l43_core_supplies[] = { + "vdd-a", "vdd-io", "vdd-cp", +}; + +static const char * const cs42l43_parent_supplies[] = { "vdd-amp" }; + +static const struct mfd_cell cs42l43_devs[] = { + { .name = "cs42l43-pinctrl", }, + { .name = "cs42l43-spi", }, + { + .name = "cs42l43-codec", + .parent_supplies = cs42l43_parent_supplies, + .num_parent_supplies = ARRAY_SIZE(cs42l43_parent_supplies), + }, +}; + +/* + * If the device is connected over Soundwire, as well as soft resetting the + * device, this function will also way for the device to detach from the bus + * before returning. + */ +static int cs42l43_soft_reset(struct cs42l43 *cs42l43) +{ + static const struct reg_sequence reset[] = { + { CS42L43_SFT_RESET, CS42L43_SFT_RESET_VAL }, + }; + + reinit_completion(&cs42l43->device_detach); + + /* + * Apply cache only because the soft reset will cause the device to + * detach from the soundwire bus. + */ + regcache_cache_only(cs42l43->regmap, true); + regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset)); + + msleep(CS42L43_RESET_DELAY); + + if (cs42l43->sdw) { + unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT); + unsigned long time; + + time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); + if (!time) { + dev_err(cs42l43->dev, "Timed out waiting for device detach\n"); + return -ETIMEDOUT; + } + } + + return -EAGAIN; +} + +/* + * This function is essentially a no-op on I2C, but will wait for the device to + * attach when the device is used on a SoundWire bus. + */ +static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43) +{ + if (!cs42l43->attached) { + unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT); + unsigned long time; + + time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); + if (!time) { + dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n"); + return -ETIMEDOUT; + } + } + + regcache_cache_only(cs42l43->regmap, false); + + /* The hardware requires enabling OSC_DIV before doing any SoundWire reads. */ + if (cs42l43->sdw) + regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL, + CS42L43_OSC_DIV2_EN_MASK); + + return 0; +} + +/* + * This function will advance the firmware into boot stage 3 from boot stage 2. + * Boot stage 3 is required to send commands to the firmware. This is achieved + * by setting the firmware NEED configuration register to zero, this indicates + * no configuration is required forcing the firmware to advance to boot stage 3. + * + * Later revisions of the firmware require the use of an alternative register + * for this purpose, which is indicated through the shadow flag. + */ +static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow) +{ + unsigned int need_reg = CS42L43_NEED_CONFIGS; + unsigned int val; + int ret; + + if (shadow) + need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS; + + regmap_write(cs42l43->regmap, need_reg, 0); + + ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS, + val, (val == CS42L43_MCU_BOOT_STAGE3), + CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); + if (ret) { + dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); + return ret; + } + + return -EAGAIN; +} + +/* + * This function will return the firmware to boot stage 2 from boot stage 3. + * Boot stage 2 is required to apply updates to the firmware. This is achieved + * by setting the firmware NEED configuration register to FW_PATCH_NEED_CFG, + * setting the HAVE configuration register to 0, and soft resetting. The + * firmware will see it is missing a patch configuration and will pause in boot + * stage 2. + * + * Note: Unlike cs42l43_mcu_stage_2_3 there is no need to consider the shadow + * register here as the driver will only return to boot stage 2 if the firmware + * requires update which means the revision does not include shadow register + * support. + */ +static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43) +{ + regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS, + CS42L43_FW_PATCH_NEED_CFG_MASK); + regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0); + + return cs42l43_soft_reset(cs42l43); +} + +/* + * Disable the firmware running on the device such that the driver can access + * the registers without fear of the MCU changing them under it. + */ +static int cs42l43_mcu_disable(struct cs42l43 *cs42l43) +{ + unsigned int val; + int ret; + + regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG, + CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL); + regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION, + CS42L43_FW_MM_CTRL_MCU_SEL_MASK); + regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK); + regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); + + ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, + (val & CS42L43_CONTROL_APPLIED_INT_MASK), + CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); + if (ret) { + dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val); + return ret; + } + + /* Soft reset to clear any register state the firmware left behind. */ + return cs42l43_soft_reset(cs42l43); +} + +/* + * Callback to load firmware updates. + */ +static void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *context) +{ + struct cs42l43 *cs42l43 = context; + const struct cs42l43_patch_header *hdr; + unsigned int loadaddr, val; + int ret; + + if (!firmware) { + dev_err(cs42l43->dev, "Failed to load firmware\n"); + cs42l43->firmware_error = -ENODEV; + goto err; + } + + hdr = (const struct cs42l43_patch_header *)&firmware->data[0]; + loadaddr = le32_to_cpu(hdr->load_addr); + + if (le16_to_cpu(hdr->version) != CS42L43_MCU_UPDATE_FORMAT) { + dev_err(cs42l43->dev, "Bad firmware file format: %d\n", hdr->version); + cs42l43->firmware_error = -EINVAL; + goto err_release; + } + + regmap_write(cs42l43->regmap, CS42L43_PATCH_START_ADDR, loadaddr); + regmap_bulk_write(cs42l43->regmap, loadaddr + CS42L43_MCU_UPDATE_OFFSET, + &firmware->data[0], firmware->size / sizeof(u32)); + + regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_PATCH_IND_MASK); + regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); + + ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, + (val & CS42L43_PATCH_APPLIED_INT_MASK), + CS42L43_MCU_POLL, CS42L43_MCU_UPDATE_TIMEOUT); + if (ret) { + dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val); + cs42l43->firmware_error = ret; + goto err_release; + } + +err_release: + release_firmware(firmware); +err: + complete(&cs42l43->firmware_download); +} + +/* + * The process of updating the firmware is split into a series of steps, at the + * end of each step a soft reset of the device might be required which will + * require the driver to wait for the device to re-attach on the SoundWire bus, + * if that control bus is being used. + */ +static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) +{ + unsigned int mcu_rev, bios_rev, boot_status, secure_cfg; + bool patched, shadow; + int ret; + + /* Clear any stale software interrupt bits. */ + regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev); + + ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status); + if (ret) { + dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret); + return ret; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev); + if (ret) { + dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret); + return ret; + } + + bios_rev = (((mcu_rev & CS42L43_BIOS_MAJOR_REV_MASK) << 12) | + ((mcu_rev & CS42L43_BIOS_MINOR_REV_MASK) << 4) | + ((mcu_rev & CS42L43_BIOS_SUBMINOR_REV_MASK) >> 8)) >> + CS42L43_BIOS_MAJOR_REV_SHIFT; + mcu_rev = ((mcu_rev & CS42L43_FW_MAJOR_REV_MASK) << 12) | + ((mcu_rev & CS42L43_FW_MINOR_REV_MASK) << 4) | + ((mcu_rev & CS42L43_FW_SUBMINOR_REV_MASK) >> 8); + + /* + * The firmware has two revision numbers bringing either of them up to a + * supported version will provide the features the driver requires. + */ + patched = mcu_rev >= CS42L43_MCU_SUPPORTED_REV || + bios_rev >= CS42L43_MCU_SUPPORTED_BIOS_REV; + /* + * Later versions of the firmwware require the driver to access some + * features through a set of shadow registers. + */ + shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV; + + ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); + if (ret) { + dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret); + return ret; + } + + cs42l43->hw_lock = secure_cfg & CS42L43_LOCK_HW_STS_MASK; + + if (!patched && cs42l43->hw_lock) { + dev_err(cs42l43->dev, "Unpatched secure device\n"); + return -EPERM; + } + + dev_dbg(cs42l43->dev, "Firmware(0x%x, 0x%x) in boot stage %d\n", + mcu_rev, bios_rev, boot_status); + + switch (boot_status) { + case CS42L43_MCU_BOOT_STAGE2: + if (!patched) { + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, + "cs42l43.bin", cs42l43->dev, + GFP_KERNEL, cs42l43, + cs42l43_mcu_load_firmware); + if (ret) { + dev_err(cs42l43->dev, "Failed to request firmware: %d\n", ret); + return ret; + } + + wait_for_completion(&cs42l43->firmware_download); + + if (cs42l43->firmware_error) + return cs42l43->firmware_error; + + return -EAGAIN; + } else { + return cs42l43_mcu_stage_2_3(cs42l43, shadow); + } + case CS42L43_MCU_BOOT_STAGE3: + if (patched) + return cs42l43_mcu_disable(cs42l43); + else + return cs42l43_mcu_stage_3_2(cs42l43); + case CS42L43_MCU_BOOT_STAGE4: + return 0; + default: + dev_err(cs42l43->dev, "Invalid boot status: %d\n", boot_status); + return -EINVAL; + } +} + +/* + * Update the firmware running on the device. + */ +static int cs42l43_mcu_update(struct cs42l43 *cs42l43) +{ + int i, ret; + + for (i = 0; i < CS42L43_MCU_UPDATE_RETRIES; i++) { + ret = cs42l43_mcu_update_step(cs42l43); + if (ret != -EAGAIN) + return ret; + + ret = cs42l43_wait_for_attach(cs42l43); + if (ret) + return ret; + } + + dev_err(cs42l43->dev, "Failed retrying update\n"); + return -ETIMEDOUT; +} + +static int cs42l43_irq_config(struct cs42l43 *cs42l43) +{ + struct irq_data *irq_data; + unsigned long irq_flags; + int ret; + + if (cs42l43->sdw) + cs42l43->irq = cs42l43->sdw->irq; + + cs42l43->irq_chip = cs42l43_irq_chip; + cs42l43->irq_chip.irq_drv_data = cs42l43; + + irq_data = irq_get_irq_data(cs42l43->irq); + if (!irq_data) { + dev_err(cs42l43->dev, "Invalid IRQ: %d\n", cs42l43->irq); + return -EINVAL; + } + + irq_flags = irqd_get_trigger_type(irq_data); + switch (irq_flags) { + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_FALLING: + break; + case IRQ_TYPE_NONE: + default: + irq_flags = IRQF_TRIGGER_LOW; + break; + } + + irq_flags |= IRQF_ONESHOT; + + ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap, + cs42l43->irq, irq_flags, 0, + &cs42l43->irq_chip, &cs42l43->irq_data); + if (ret) { + dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret); + return ret; + } + + dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n", + cs42l43->irq, irq_flags); + + return 0; +} + +static void cs42l43_boot_work(struct work_struct *work) +{ + struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work); + unsigned int devid, revid, otp; + int ret; + + ret = cs42l43_wait_for_attach(cs42l43); + if (ret) + goto err; + + ret = regmap_read(cs42l43->regmap, CS42L43_DEVID, &devid); + if (ret) { + dev_err(cs42l43->dev, "Failed to read devid: %d\n", ret); + goto err; + } + + switch (devid) { + case CS42L43_DEVID_VAL: + break; + default: + dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid); + goto err; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid); + if (ret) { + dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret); + goto err; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_OTP_REVISION_ID, &otp); + if (ret) { + dev_err(cs42l43->dev, "Failed to read otp rev: %d\n", ret); + goto err; + } + + dev_info(cs42l43->dev, + "devid: 0x%06x, rev: 0x%02x, otp: 0x%02x\n", devid, revid, otp); + + ret = cs42l43_mcu_update(cs42l43); + if (ret) + goto err; + + ret = regmap_register_patch(cs42l43->regmap, cs42l43_reva_patch, + ARRAY_SIZE(cs42l43_reva_patch)); + if (ret) { + dev_err(cs42l43->dev, "Failed to apply register patch: %d\n", ret); + goto err; + } + + ret = cs42l43_irq_config(cs42l43); + if (ret) + goto err; + + ret = devm_mfd_add_devices(cs42l43->dev, PLATFORM_DEVID_NONE, + cs42l43_devs, ARRAY_SIZE(cs42l43_devs), + NULL, 0, NULL); + if (ret) { + dev_err(cs42l43->dev, "Failed to add subdevices: %d\n", ret); + goto err; + } + + pm_runtime_mark_last_busy(cs42l43->dev); + pm_runtime_put_autosuspend(cs42l43->dev); + + return; + +err: + pm_runtime_put_sync(cs42l43->dev); + cs42l43_dev_remove(cs42l43); +} + +static int cs42l43_power_up(struct cs42l43 *cs42l43) +{ + int ret; + + ret = regulator_enable(cs42l43->vdd_p); + if (ret) { + dev_err(cs42l43->dev, "Failed to enable vdd-p: %d\n", ret); + return ret; + } + + /* vdd-p must be on for 50uS before any other supply */ + usleep_range(CS42L43_VDDP_DELAY, 2 * CS42L43_VDDP_DELAY); + + gpiod_set_value_cansleep(cs42l43->reset, 1); + + ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); + if (ret) { + dev_err(cs42l43->dev, "Failed to enable core supplies: %d\n", ret); + goto err_reset; + } + + ret = regulator_enable(cs42l43->vdd_d); + if (ret) { + dev_err(cs42l43->dev, "Failed to enable vdd-d: %d\n", ret); + goto err_core_supplies; + } + + usleep_range(CS42L43_VDDD_DELAY, 2 * CS42L43_VDDD_DELAY); + + return 0; + +err_core_supplies: + regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); +err_reset: + gpiod_set_value_cansleep(cs42l43->reset, 0); + regulator_disable(cs42l43->vdd_p); + + return ret; +} + +static int cs42l43_power_down(struct cs42l43 *cs42l43) +{ + int ret; + + ret = regulator_disable(cs42l43->vdd_d); + if (ret) { + dev_err(cs42l43->dev, "Failed to disable vdd-d: %d\n", ret); + return ret; + } + + ret = regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); + if (ret) { + dev_err(cs42l43->dev, "Failed to disable core supplies: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(cs42l43->reset, 0); + + ret = regulator_disable(cs42l43->vdd_p); + if (ret) { + dev_err(cs42l43->dev, "Failed to disable vdd-p: %d\n", ret); + return ret; + } + + return 0; +} + +int cs42l43_dev_probe(struct cs42l43 *cs42l43) +{ + int i, ret; + + dev_set_drvdata(cs42l43->dev, cs42l43); + + mutex_init(&cs42l43->pll_lock); + init_completion(&cs42l43->device_attach); + init_completion(&cs42l43->device_detach); + init_completion(&cs42l43->firmware_download); + INIT_WORK(&cs42l43->boot_work, cs42l43_boot_work); + + regcache_cache_only(cs42l43->regmap, true); + + cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs42l43->reset)) + return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), + "Failed to get reset\n"); + + cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); + if (IS_ERR(cs42l43->vdd_p)) + return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), + "Failed to get vdd-p\n"); + + cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d"); + if (IS_ERR(cs42l43->vdd_d)) + return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d), + "Failed to get vdd-d\n"); + + BUILD_BUG_ON(ARRAY_SIZE(cs42l43_core_supplies) != CS42L43_N_SUPPLIES); + + for (i = 0; i < CS42L43_N_SUPPLIES; i++) + cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i]; + + ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES, + cs42l43->core_supplies); + if (ret) + return dev_err_probe(cs42l43->dev, ret, + "Failed to get core supplies\n"); + + ret = cs42l43_power_up(cs42l43); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME); + pm_runtime_use_autosuspend(cs42l43->dev); + pm_runtime_set_active(cs42l43->dev); + /* + * The device is already powered up, but keep it from suspending until + * the boot work runs. + */ + pm_runtime_get_noresume(cs42l43->dev); + devm_pm_runtime_enable(cs42l43->dev); + + queue_work(system_long_wq, &cs42l43->boot_work); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43); + +void cs42l43_dev_remove(struct cs42l43 *cs42l43) +{ + cs42l43_power_down(cs42l43); +} +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43); + +static int cs42l43_suspend(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + int ret; + + /* + * Don't care about being resumed here, but the driver does want + * force_resume to always trigger an actual resume, so that register + * state for the MCU/GPIOs is returned as soon as possible after system + * resume. force_resume will resume if the reference count is resumed on + * suspend hence the get_noresume. + */ + pm_runtime_get_noresume(dev); + + ret = pm_runtime_force_suspend(dev); + if (ret) { + dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret); + pm_runtime_put_noidle(dev); + return ret; + } + + pm_runtime_put_noidle(dev); + + ret = cs42l43_power_down(cs42l43); + if (ret) + return ret; + + return 0; +} + +static int cs42l43_resume(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + int ret; + + ret = cs42l43_power_up(cs42l43); + if (ret) + return ret; + + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); + return ret; + } + + return 0; +} + +static int cs42l43_runtime_suspend(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + /* + * Whilst the driver doesn't power the chip down here, going into runtime + * suspend lets the SoundWire bus power down, which means the driver + * can't communicate with the device any more. + */ + regcache_cache_only(cs42l43->regmap, true); + + return 0; +} + +static int cs42l43_runtime_resume(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + unsigned int reset_canary; + int ret; + + ret = cs42l43_wait_for_attach(cs42l43); + if (ret) + return ret; + + ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary); + if (ret) { + dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret); + goto err; + } + + if (!reset_canary) { + /* + * If the canary has cleared the chip has reset, re-handle the + * MCU and mark the cache as dirty to indicate the chip reset. + */ + ret = cs42l43_mcu_update(cs42l43); + if (ret) + goto err; + + regcache_mark_dirty(cs42l43->regmap); + } + + ret = regcache_sync(cs42l43->regmap); + if (ret) { + dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret); + goto err; + } + + return 0; + +err: + regcache_cache_only(cs42l43->regmap, true); + + return ret; +} + +EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { + SET_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) + SET_RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) +}; + +MODULE_DESCRIPTION("CS42L43 Core Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("cs42l43.bin"); diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h new file mode 100644 index 000000000000..eb4caf393833 --- /dev/null +++ b/drivers/mfd/cs42l43.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS42L43 core driver internal data + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include + +#ifndef CS42L43_CORE_INT_H +#define CS42L43_CORE_INT_H + +#define CS42L43_N_DEFAULTS 176 + +extern const struct dev_pm_ops cs42l43_pm_ops; +extern const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS]; + +bool cs42l43_readable_register(struct device *dev, unsigned int reg); +bool cs42l43_precious_register(struct device *dev, unsigned int reg); +bool cs42l43_volatile_register(struct device *dev, unsigned int reg); + +int cs42l43_dev_probe(struct cs42l43 *cs42l43); +void cs42l43_dev_remove(struct cs42l43 *cs42l43); + +#endif /* CS42L43_CORE_INT_H */ diff --git a/include/linux/mfd/cs42l43-regs.h b/include/linux/mfd/cs42l43-regs.h new file mode 100644 index 000000000000..c39a49269cb7 --- /dev/null +++ b/include/linux/mfd/cs42l43-regs.h @@ -0,0 +1,1184 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cs42l43 register definitions + * + * Copyright (c) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef CS42L43_CORE_REGS_H +#define CS42L43_CORE_REGS_H + +/* Registers */ +#define CS42L43_GEN_INT_STAT_1 0x000000C0 +#define CS42L43_GEN_INT_MASK_1 0x000000C1 +#define CS42L43_DEVID 0x00003000 +#define CS42L43_REVID 0x00003004 +#define CS42L43_RELID 0x0000300C +#define CS42L43_SFT_RESET 0x00003020 +#define CS42L43_DRV_CTRL1 0x00006004 +#define CS42L43_DRV_CTRL3 0x0000600C +#define CS42L43_DRV_CTRL4 0x00006010 +#define CS42L43_DRV_CTRL_5 0x00006014 +#define CS42L43_GPIO_CTRL1 0x00006034 +#define CS42L43_GPIO_CTRL2 0x00006038 +#define CS42L43_GPIO_STS 0x0000603C +#define CS42L43_GPIO_FN_SEL 0x00006040 +#define CS42L43_MCLK_SRC_SEL 0x00007004 +#define CS42L43_CCM_BLK_CLK_CONTROL 0x00007010 +#define CS42L43_SAMPLE_RATE1 0x00007014 +#define CS42L43_SAMPLE_RATE2 0x00007018 +#define CS42L43_SAMPLE_RATE3 0x0000701C +#define CS42L43_SAMPLE_RATE4 0x00007020 +#define CS42L43_PLL_CONTROL 0x00007034 +#define CS42L43_FS_SELECT1 0x00007038 +#define CS42L43_FS_SELECT2 0x0000703C +#define CS42L43_FS_SELECT3 0x00007040 +#define CS42L43_FS_SELECT4 0x00007044 +#define CS42L43_PDM_CONTROL 0x0000704C +#define CS42L43_ASP_CLK_CONFIG1 0x00007058 +#define CS42L43_ASP_CLK_CONFIG2 0x0000705C +#define CS42L43_OSC_DIV_SEL 0x00007068 +#define CS42L43_ADC_B_CTRL1 0x00008000 +#define CS42L43_ADC_B_CTRL2 0x00008004 +#define CS42L43_DECIM_HPF_WNF_CTRL1 0x0000803C +#define CS42L43_DECIM_HPF_WNF_CTRL2 0x00008040 +#define CS42L43_DECIM_HPF_WNF_CTRL3 0x00008044 +#define CS42L43_DECIM_HPF_WNF_CTRL4 0x00008048 +#define CS42L43_DMIC_PDM_CTRL 0x0000804C +#define CS42L43_DECIM_VOL_CTRL_CH1_CH2 0x00008050 +#define CS42L43_DECIM_VOL_CTRL_CH3_CH4 0x00008054 +#define CS42L43_DECIM_VOL_CTRL_UPDATE 0x00008058 +#define CS42L43_INTP_VOLUME_CTRL1 0x00009008 +#define CS42L43_INTP_VOLUME_CTRL2 0x0000900C +#define CS42L43_AMP1_2_VOL_RAMP 0x00009010 +#define CS42L43_ASP_CTRL 0x0000A000 +#define CS42L43_ASP_FSYNC_CTRL1 0x0000A004 +#define CS42L43_ASP_FSYNC_CTRL2 0x0000A008 +#define CS42L43_ASP_FSYNC_CTRL3 0x0000A00C +#define CS42L43_ASP_FSYNC_CTRL4 0x0000A010 +#define CS42L43_ASP_DATA_CTRL 0x0000A018 +#define CS42L43_ASP_RX_EN 0x0000A020 +#define CS42L43_ASP_TX_EN 0x0000A024 +#define CS42L43_ASP_RX_CH1_CTRL 0x0000A028 +#define CS42L43_ASP_RX_CH2_CTRL 0x0000A02C +#define CS42L43_ASP_RX_CH3_CTRL 0x0000A030 +#define CS42L43_ASP_RX_CH4_CTRL 0x0000A034 +#define CS42L43_ASP_RX_CH5_CTRL 0x0000A038 +#define CS42L43_ASP_RX_CH6_CTRL 0x0000A03C +#define CS42L43_ASP_TX_CH1_CTRL 0x0000A068 +#define CS42L43_ASP_TX_CH2_CTRL 0x0000A06C +#define CS42L43_ASP_TX_CH3_CTRL 0x0000A070 +#define CS42L43_ASP_TX_CH4_CTRL 0x0000A074 +#define CS42L43_ASP_TX_CH5_CTRL 0x0000A078 +#define CS42L43_ASP_TX_CH6_CTRL 0x0000A07C +#define CS42L43_OTP_REVISION_ID 0x0000B02C +#define CS42L43_ASPTX1_INPUT 0x0000C200 +#define CS42L43_ASPTX2_INPUT 0x0000C210 +#define CS42L43_ASPTX3_INPUT 0x0000C220 +#define CS42L43_ASPTX4_INPUT 0x0000C230 +#define CS42L43_ASPTX5_INPUT 0x0000C240 +#define CS42L43_ASPTX6_INPUT 0x0000C250 +#define CS42L43_SWIRE_DP1_CH1_INPUT 0x0000C280 +#define CS42L43_SWIRE_DP1_CH2_INPUT 0x0000C290 +#define CS42L43_SWIRE_DP1_CH3_INPUT 0x0000C2A0 +#define CS42L43_SWIRE_DP1_CH4_INPUT 0x0000C2B0 +#define CS42L43_SWIRE_DP2_CH1_INPUT 0x0000C2C0 +#define CS42L43_SWIRE_DP2_CH2_INPUT 0x0000C2D0 +#define CS42L43_SWIRE_DP3_CH1_INPUT 0x0000C2E0 +#define CS42L43_SWIRE_DP3_CH2_INPUT 0x0000C2F0 +#define CS42L43_SWIRE_DP4_CH1_INPUT 0x0000C300 +#define CS42L43_SWIRE_DP4_CH2_INPUT 0x0000C310 +#define CS42L43_ASRC_INT1_INPUT1 0x0000C400 +#define CS42L43_ASRC_INT2_INPUT1 0x0000C410 +#define CS42L43_ASRC_INT3_INPUT1 0x0000C420 +#define CS42L43_ASRC_INT4_INPUT1 0x0000C430 +#define CS42L43_ASRC_DEC1_INPUT1 0x0000C440 +#define CS42L43_ASRC_DEC2_INPUT1 0x0000C450 +#define CS42L43_ASRC_DEC3_INPUT1 0x0000C460 +#define CS42L43_ASRC_DEC4_INPUT1 0x0000C470 +#define CS42L43_ISRC1INT1_INPUT1 0x0000C500 +#define CS42L43_ISRC1INT2_INPUT1 0x0000C510 +#define CS42L43_ISRC1DEC1_INPUT1 0x0000C520 +#define CS42L43_ISRC1DEC2_INPUT1 0x0000C530 +#define CS42L43_ISRC2INT1_INPUT1 0x0000C540 +#define CS42L43_ISRC2INT2_INPUT1 0x0000C550 +#define CS42L43_ISRC2DEC1_INPUT1 0x0000C560 +#define CS42L43_ISRC2DEC2_INPUT1 0x0000C570 +#define CS42L43_EQ1MIX_INPUT1 0x0000C580 +#define CS42L43_EQ1MIX_INPUT2 0x0000C584 +#define CS42L43_EQ1MIX_INPUT3 0x0000C588 +#define CS42L43_EQ1MIX_INPUT4 0x0000C58C +#define CS42L43_EQ2MIX_INPUT1 0x0000C590 +#define CS42L43_EQ2MIX_INPUT2 0x0000C594 +#define CS42L43_EQ2MIX_INPUT3 0x0000C598 +#define CS42L43_EQ2MIX_INPUT4 0x0000C59C +#define CS42L43_SPDIF1_INPUT1 0x0000C600 +#define CS42L43_SPDIF2_INPUT1 0x0000C610 +#define CS42L43_AMP1MIX_INPUT1 0x0000C620 +#define CS42L43_AMP1MIX_INPUT2 0x0000C624 +#define CS42L43_AMP1MIX_INPUT3 0x0000C628 +#define CS42L43_AMP1MIX_INPUT4 0x0000C62C +#define CS42L43_AMP2MIX_INPUT1 0x0000C630 +#define CS42L43_AMP2MIX_INPUT2 0x0000C634 +#define CS42L43_AMP2MIX_INPUT3 0x0000C638 +#define CS42L43_AMP2MIX_INPUT4 0x0000C63C +#define CS42L43_AMP3MIX_INPUT1 0x0000C640 +#define CS42L43_AMP3MIX_INPUT2 0x0000C644 +#define CS42L43_AMP3MIX_INPUT3 0x0000C648 +#define CS42L43_AMP3MIX_INPUT4 0x0000C64C +#define CS42L43_AMP4MIX_INPUT1 0x0000C650 +#define CS42L43_AMP4MIX_INPUT2 0x0000C654 +#define CS42L43_AMP4MIX_INPUT3 0x0000C658 +#define CS42L43_AMP4MIX_INPUT4 0x0000C65C +#define CS42L43_ASRC_INT_ENABLES 0x0000E000 +#define CS42L43_ASRC_DEC_ENABLES 0x0000E004 +#define CS42L43_PDNCNTL 0x00010000 +#define CS42L43_RINGSENSE_DEB_CTRL 0x0001001C +#define CS42L43_TIPSENSE_DEB_CTRL 0x00010020 +#define CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS 0x00010028 +#define CS42L43_HS2 0x00010040 +#define CS42L43_HS_STAT 0x00010048 +#define CS42L43_MCU_SW_INTERRUPT 0x00010094 +#define CS42L43_STEREO_MIC_CTRL 0x000100A4 +#define CS42L43_STEREO_MIC_CLAMP_CTRL 0x000100C4 +#define CS42L43_BLOCK_EN2 0x00010104 +#define CS42L43_BLOCK_EN3 0x00010108 +#define CS42L43_BLOCK_EN4 0x0001010C +#define CS42L43_BLOCK_EN5 0x00010110 +#define CS42L43_BLOCK_EN6 0x00010114 +#define CS42L43_BLOCK_EN7 0x00010118 +#define CS42L43_BLOCK_EN8 0x0001011C +#define CS42L43_BLOCK_EN9 0x00010120 +#define CS42L43_BLOCK_EN10 0x00010124 +#define CS42L43_BLOCK_EN11 0x00010128 +#define CS42L43_TONE_CH1_CTRL 0x00010134 +#define CS42L43_TONE_CH2_CTRL 0x00010138 +#define CS42L43_MIC_DETECT_CONTROL_1 0x00011074 +#define CS42L43_DETECT_STATUS_1 0x0001107C +#define CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL 0x00011090 +#define CS42L43_MIC_DETECT_CONTROL_ANDROID 0x000110B0 +#define CS42L43_ISRC1_CTRL 0x00012004 +#define CS42L43_ISRC2_CTRL 0x00013004 +#define CS42L43_CTRL_REG 0x00014000 +#define CS42L43_FDIV_FRAC 0x00014004 +#define CS42L43_CAL_RATIO 0x00014008 +#define CS42L43_SPI_CLK_CONFIG1 0x00016004 +#define CS42L43_SPI_CONFIG1 0x00016010 +#define CS42L43_SPI_CONFIG2 0x00016014 +#define CS42L43_SPI_CONFIG3 0x00016018 +#define CS42L43_SPI_CONFIG4 0x00016024 +#define CS42L43_SPI_STATUS1 0x00016100 +#define CS42L43_SPI_STATUS2 0x00016104 +#define CS42L43_TRAN_CONFIG1 0x00016200 +#define CS42L43_TRAN_CONFIG2 0x00016204 +#define CS42L43_TRAN_CONFIG3 0x00016208 +#define CS42L43_TRAN_CONFIG4 0x0001620C +#define CS42L43_TRAN_CONFIG5 0x00016220 +#define CS42L43_TRAN_CONFIG6 0x00016224 +#define CS42L43_TRAN_CONFIG7 0x00016228 +#define CS42L43_TRAN_CONFIG8 0x0001622C +#define CS42L43_TRAN_STATUS1 0x00016300 +#define CS42L43_TRAN_STATUS2 0x00016304 +#define CS42L43_TRAN_STATUS3 0x00016308 +#define CS42L43_TX_DATA 0x00016400 +#define CS42L43_RX_DATA 0x00016600 +#define CS42L43_DACCNFG1 0x00017000 +#define CS42L43_DACCNFG2 0x00017004 +#define CS42L43_HPPATHVOL 0x0001700C +#define CS42L43_PGAVOL 0x00017014 +#define CS42L43_LOADDETRESULTS 0x00017018 +#define CS42L43_LOADDETENA 0x00017024 +#define CS42L43_CTRL 0x00017028 +#define CS42L43_COEFF_DATA_IN0 0x00018000 +#define CS42L43_COEFF_RD_WR0 0x00018008 +#define CS42L43_INIT_DONE0 0x00018010 +#define CS42L43_START_EQZ0 0x00018014 +#define CS42L43_MUTE_EQ_IN0 0x0001801C +#define CS42L43_DECIM_INT 0x0001B000 +#define CS42L43_EQ_INT 0x0001B004 +#define CS42L43_ASP_INT 0x0001B008 +#define CS42L43_PLL_INT 0x0001B00C +#define CS42L43_SOFT_INT 0x0001B010 +#define CS42L43_SWIRE_INT 0x0001B014 +#define CS42L43_MSM_INT 0x0001B018 +#define CS42L43_ACC_DET_INT 0x0001B01C +#define CS42L43_I2C_TGT_INT 0x0001B020 +#define CS42L43_SPI_MSTR_INT 0x0001B024 +#define CS42L43_SW_TO_SPI_BRIDGE_INT 0x0001B028 +#define CS42L43_OTP_INT 0x0001B02C +#define CS42L43_CLASS_D_AMP_INT 0x0001B030 +#define CS42L43_GPIO_INT 0x0001B034 +#define CS42L43_ASRC_INT 0x0001B038 +#define CS42L43_HPOUT_INT 0x0001B03C +#define CS42L43_DECIM_MASK 0x0001B0A0 +#define CS42L43_EQ_MIX_MASK 0x0001B0A4 +#define CS42L43_ASP_MASK 0x0001B0A8 +#define CS42L43_PLL_MASK 0x0001B0AC +#define CS42L43_SOFT_MASK 0x0001B0B0 +#define CS42L43_SWIRE_MASK 0x0001B0B4 +#define CS42L43_MSM_MASK 0x0001B0B8 +#define CS42L43_ACC_DET_MASK 0x0001B0BC +#define CS42L43_I2C_TGT_MASK 0x0001B0C0 +#define CS42L43_SPI_MSTR_MASK 0x0001B0C4 +#define CS42L43_SW_TO_SPI_BRIDGE_MASK 0x0001B0C8 +#define CS42L43_OTP_MASK 0x0001B0CC +#define CS42L43_CLASS_D_AMP_MASK 0x0001B0D0 +#define CS42L43_GPIO_INT_MASK 0x0001B0D4 +#define CS42L43_ASRC_MASK 0x0001B0D8 +#define CS42L43_HPOUT_MASK 0x0001B0DC +#define CS42L43_DECIM_INT_SHADOW 0x0001B300 +#define CS42L43_EQ_MIX_INT_SHADOW 0x0001B304 +#define CS42L43_ASP_INT_SHADOW 0x0001B308 +#define CS42L43_PLL_INT_SHADOW 0x0001B30C +#define CS42L43_SOFT_INT_SHADOW 0x0001B310 +#define CS42L43_SWIRE_INT_SHADOW 0x0001B314 +#define CS42L43_MSM_INT_SHADOW 0x0001B318 +#define CS42L43_ACC_DET_INT_SHADOW 0x0001B31C +#define CS42L43_I2C_TGT_INT_SHADOW 0x0001B320 +#define CS42L43_SPI_MSTR_INT_SHADOW 0x0001B324 +#define CS42L43_SW_TO_SPI_BRIDGE_SHADOW 0x0001B328 +#define CS42L43_OTP_INT_SHADOW 0x0001B32C +#define CS42L43_CLASS_D_AMP_INT_SHADOW 0x0001B330 +#define CS42L43_GPIO_SHADOW 0x0001B334 +#define CS42L43_ASRC_SHADOW 0x0001B338 +#define CS42L43_HP_OUT_SHADOW 0x0001B33C +#define CS42L43_BOOT_CONTROL 0x00101000 +#define CS42L43_BLOCK_EN 0x00101008 +#define CS42L43_SHUTTER_CONTROL 0x0010100C +#define CS42L43_MCU_SW_REV 0x00114000 +#define CS42L43_PATCH_START_ADDR 0x00114004 +#define CS42L43_NEED_CONFIGS 0x0011400C +#define CS42L43_BOOT_STATUS 0x0011401C +#define CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS 0x0011F8F8 +#define CS42L43_FW_MISSION_CTRL_NEED_CONFIGS 0x0011FE00 +#define CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS 0x0011FE04 +#define CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION 0x0011FE0C +#define CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG 0x0011FE10 +#define CS42L43_MCU_RAM_MAX 0x0011FFFF + +/* CS42L43_DEVID */ +#define CS42L43_DEVID_VAL 0x00042A43 + +/* CS42L43_GEN_INT_STAT_1 */ +#define CS42L43_INT_STAT_GEN1_MASK 0x00000001 +#define CS42L43_INT_STAT_GEN1_SHIFT 0 + +/* CS42L43_SFT_RESET */ +#define CS42L43_SFT_RESET_MASK 0xFF000000 +#define CS42L43_SFT_RESET_SHIFT 24 + +#define CS42L43_SFT_RESET_VAL 0x5A000000 + +/* CS42L43_DRV_CTRL1 */ +#define CS42L43_ASP_DOUT_DRV_MASK 0x00038000 +#define CS42L43_ASP_DOUT_DRV_SHIFT 15 +#define CS42L43_ASP_FSYNC_DRV_MASK 0x00000E00 +#define CS42L43_ASP_FSYNC_DRV_SHIFT 9 +#define CS42L43_ASP_BCLK_DRV_MASK 0x000001C0 +#define CS42L43_ASP_BCLK_DRV_SHIFT 6 + +/* CS42L43_DRV_CTRL3 */ +#define CS42L43_I2C_ADDR_DRV_MASK 0x30000000 +#define CS42L43_I2C_ADDR_DRV_SHIFT 28 +#define CS42L43_I2C_SDA_DRV_MASK 0x0C000000 +#define CS42L43_I2C_SDA_DRV_SHIFT 26 +#define CS42L43_PDMOUT2_CLK_DRV_MASK 0x00E00000 +#define CS42L43_PDMOUT2_CLK_DRV_SHIFT 21 +#define CS42L43_PDMOUT2_DATA_DRV_MASK 0x001C0000 +#define CS42L43_PDMOUT2_DATA_DRV_SHIFT 18 +#define CS42L43_PDMOUT1_CLK_DRV_MASK 0x00038000 +#define CS42L43_PDMOUT1_CLK_DRV_SHIFT 15 +#define CS42L43_PDMOUT1_DATA_DRV_MASK 0x00007000 +#define CS42L43_PDMOUT1_DATA_DRV_SHIFT 12 +#define CS42L43_SPI_MISO_DRV_MASK 0x00000038 +#define CS42L43_SPI_MISO_DRV_SHIFT 3 + +/* CS42L43_DRV_CTRL4 */ +#define CS42L43_GPIO3_DRV_MASK 0x00000E00 +#define CS42L43_GPIO3_DRV_SHIFT 9 +#define CS42L43_GPIO2_DRV_MASK 0x000001C0 +#define CS42L43_GPIO2_DRV_SHIFT 6 +#define CS42L43_GPIO1_DRV_MASK 0x00000038 +#define CS42L43_GPIO1_DRV_SHIFT 3 + +/* CS42L43_DRV_CTRL_5 */ +#define CS42L43_I2C_SCL_DRV_MASK 0x18000000 +#define CS42L43_I2C_SCL_DRV_SHIFT 27 +#define CS42L43_SPI_SCK_DRV_MASK 0x07000000 +#define CS42L43_SPI_SCK_DRV_SHIFT 24 +#define CS42L43_SPI_MOSI_DRV_MASK 0x00E00000 +#define CS42L43_SPI_MOSI_DRV_SHIFT 21 +#define CS42L43_SPI_SSB_DRV_MASK 0x001C0000 +#define CS42L43_SPI_SSB_DRV_SHIFT 18 +#define CS42L43_ASP_DIN_DRV_MASK 0x000001C0 +#define CS42L43_ASP_DIN_DRV_SHIFT 6 + +/* CS42L43_GPIO_CTRL1 */ +#define CS42L43_GPIO3_POL_MASK 0x00040000 +#define CS42L43_GPIO3_POL_SHIFT 18 +#define CS42L43_GPIO2_POL_MASK 0x00020000 +#define CS42L43_GPIO2_POL_SHIFT 17 +#define CS42L43_GPIO1_POL_MASK 0x00010000 +#define CS42L43_GPIO1_POL_SHIFT 16 +#define CS42L43_GPIO3_LVL_MASK 0x00000400 +#define CS42L43_GPIO3_LVL_SHIFT 10 +#define CS42L43_GPIO2_LVL_MASK 0x00000200 +#define CS42L43_GPIO2_LVL_SHIFT 9 +#define CS42L43_GPIO1_LVL_MASK 0x00000100 +#define CS42L43_GPIO1_LVL_SHIFT 8 +#define CS42L43_GPIO3_DIR_MASK 0x00000004 +#define CS42L43_GPIO3_DIR_SHIFT 2 +#define CS42L43_GPIO2_DIR_MASK 0x00000002 +#define CS42L43_GPIO2_DIR_SHIFT 1 +#define CS42L43_GPIO1_DIR_MASK 0x00000001 +#define CS42L43_GPIO1_DIR_SHIFT 0 + +/* CS42L43_GPIO_CTRL2 */ +#define CS42L43_GPIO3_DEGLITCH_BYP_MASK 0x00000004 +#define CS42L43_GPIO3_DEGLITCH_BYP_SHIFT 2 +#define CS42L43_GPIO2_DEGLITCH_BYP_MASK 0x00000002 +#define CS42L43_GPIO2_DEGLITCH_BYP_SHIFT 1 +#define CS42L43_GPIO1_DEGLITCH_BYP_MASK 0x00000001 +#define CS42L43_GPIO1_DEGLITCH_BYP_SHIFT 0 + +/* CS42L43_GPIO_STS */ +#define CS42L43_GPIO3_STS_MASK 0x00000004 +#define CS42L43_GPIO3_STS_SHIFT 2 +#define CS42L43_GPIO2_STS_MASK 0x00000002 +#define CS42L43_GPIO2_STS_SHIFT 1 +#define CS42L43_GPIO1_STS_MASK 0x00000001 +#define CS42L43_GPIO1_STS_SHIFT 0 + +/* CS42L43_GPIO_FN_SEL */ +#define CS42L43_GPIO3_FN_SEL_MASK 0x00000004 +#define CS42L43_GPIO3_FN_SEL_SHIFT 2 +#define CS42L43_GPIO1_FN_SEL_MASK 0x00000001 +#define CS42L43_GPIO1_FN_SEL_SHIFT 0 + +/* CS42L43_MCLK_SRC_SEL */ +#define CS42L43_OSC_PLL_MCLK_SEL_MASK 0x00000001 +#define CS42L43_OSC_PLL_MCLK_SEL_SHIFT 0 + +/* CS42L43_SAMPLE_RATE1..CS42L43_SAMPLE_RATE4 */ +#define CS42L43_SAMPLE_RATE_MASK 0x0000001F +#define CS42L43_SAMPLE_RATE_SHIFT 0 + +/* CS42L43_PLL_CONTROL */ +#define CS42L43_PLL_REFCLK_EN_MASK 0x00000008 +#define CS42L43_PLL_REFCLK_EN_SHIFT 3 +#define CS42L43_PLL_REFCLK_DIV_MASK 0x00000006 +#define CS42L43_PLL_REFCLK_DIV_SHIFT 1 +#define CS42L43_PLL_REFCLK_SRC_MASK 0x00000001 +#define CS42L43_PLL_REFCLK_SRC_SHIFT 0 + +/* CS42L43_FS_SELECT1 */ +#define CS42L43_ASP_RATE_MASK 0x00000003 +#define CS42L43_ASP_RATE_SHIFT 0 + +/* CS42L43_FS_SELECT2 */ +#define CS42L43_ASRC_DEC_OUT_RATE_MASK 0x000000C0 +#define CS42L43_ASRC_DEC_OUT_RATE_SHIFT 6 +#define CS42L43_ASRC_INT_OUT_RATE_MASK 0x00000030 +#define CS42L43_ASRC_INT_OUT_RATE_SHIFT 4 +#define CS42L43_ASRC_DEC_IN_RATE_MASK 0x0000000C +#define CS42L43_ASRC_DEC_IN_RATE_SHIFT 2 +#define CS42L43_ASRC_INT_IN_RATE_MASK 0x00000003 +#define CS42L43_ASRC_INT_IN_RATE_SHIFT 0 + +/* CS42L43_FS_SELECT3 */ +#define CS42L43_HPOUT_RATE_MASK 0x0000C000 +#define CS42L43_HPOUT_RATE_SHIFT 14 +#define CS42L43_EQZ_RATE_MASK 0x00003000 +#define CS42L43_EQZ_RATE_SHIFT 12 +#define CS42L43_DIAGGEN_RATE_MASK 0x00000C00 +#define CS42L43_DIAGGEN_RATE_SHIFT 10 +#define CS42L43_DECIM_CH4_RATE_MASK 0x00000300 +#define CS42L43_DECIM_CH4_RATE_SHIFT 8 +#define CS42L43_DECIM_CH3_RATE_MASK 0x000000C0 +#define CS42L43_DECIM_CH3_RATE_SHIFT 6 +#define CS42L43_DECIM_CH2_RATE_MASK 0x00000030 +#define CS42L43_DECIM_CH2_RATE_SHIFT 4 +#define CS42L43_DECIM_CH1_RATE_MASK 0x0000000C +#define CS42L43_DECIM_CH1_RATE_SHIFT 2 +#define CS42L43_AMP1_2_RATE_MASK 0x00000003 +#define CS42L43_AMP1_2_RATE_SHIFT 0 + +/* CS42L43_FS_SELECT4 */ +#define CS42L43_SW_DP7_RATE_MASK 0x00C00000 +#define CS42L43_SW_DP7_RATE_SHIFT 22 +#define CS42L43_SW_DP6_RATE_MASK 0x00300000 +#define CS42L43_SW_DP6_RATE_SHIFT 20 +#define CS42L43_SPDIF_RATE_MASK 0x000C0000 +#define CS42L43_SPDIF_RATE_SHIFT 18 +#define CS42L43_SW_DP5_RATE_MASK 0x00030000 +#define CS42L43_SW_DP5_RATE_SHIFT 16 +#define CS42L43_SW_DP4_RATE_MASK 0x0000C000 +#define CS42L43_SW_DP4_RATE_SHIFT 14 +#define CS42L43_SW_DP3_RATE_MASK 0x00003000 +#define CS42L43_SW_DP3_RATE_SHIFT 12 +#define CS42L43_SW_DP2_RATE_MASK 0x00000C00 +#define CS42L43_SW_DP2_RATE_SHIFT 10 +#define CS42L43_SW_DP1_RATE_MASK 0x00000300 +#define CS42L43_SW_DP1_RATE_SHIFT 8 +#define CS42L43_ISRC2_LOW_RATE_MASK 0x000000C0 +#define CS42L43_ISRC2_LOW_RATE_SHIFT 6 +#define CS42L43_ISRC2_HIGH_RATE_MASK 0x00000030 +#define CS42L43_ISRC2_HIGH_RATE_SHIFT 4 +#define CS42L43_ISRC1_LOW_RATE_MASK 0x0000000C +#define CS42L43_ISRC1_LOW_RATE_SHIFT 2 +#define CS42L43_ISRC1_HIGH_RATE_MASK 0x00000003 +#define CS42L43_ISRC1_HIGH_RATE_SHIFT 0 + +/* CS42L43_PDM_CONTROL */ +#define CS42L43_PDM2_CLK_DIV_MASK 0x0000000C +#define CS42L43_PDM2_CLK_DIV_SHIFT 2 +#define CS42L43_PDM1_CLK_DIV_MASK 0x00000003 +#define CS42L43_PDM1_CLK_DIV_SHIFT 0 + +/* CS42L43_ASP_CLK_CONFIG1 */ +#define CS42L43_ASP_BCLK_N_MASK 0x03FF0000 +#define CS42L43_ASP_BCLK_N_SHIFT 16 +#define CS42L43_ASP_BCLK_M_MASK 0x000003FF +#define CS42L43_ASP_BCLK_M_SHIFT 0 + +/* CS42L43_ASP_CLK_CONFIG2 */ +#define CS42L43_ASP_MASTER_MODE_MASK 0x00000002 +#define CS42L43_ASP_MASTER_MODE_SHIFT 1 +#define CS42L43_ASP_BCLK_INV_MASK 0x00000001 +#define CS42L43_ASP_BCLK_INV_SHIFT 0 + +/* CS42L43_OSC_DIV_SEL */ +#define CS42L43_OSC_DIV2_EN_MASK 0x00000001 +#define CS42L43_OSC_DIV2_EN_SHIFT 0 + +/* CS42L43_ADC_B_CTRL1..CS42L43_ADC_B_CTRL1 */ +#define CS42L43_PGA_WIDESWING_MODE_EN_MASK 0x00000080 +#define CS42L43_PGA_WIDESWING_MODE_EN_SHIFT 7 +#define CS42L43_ADC_AIN_SEL_MASK 0x00000010 +#define CS42L43_ADC_AIN_SEL_SHIFT 4 +#define CS42L43_ADC_PGA_GAIN_MASK 0x0000000F +#define CS42L43_ADC_PGA_GAIN_SHIFT 0 + +/* CS42L43_DECIM_HPF_WNF_CTRL1..CS42L43_DECIM_HPF_WNF_CTRL4 */ +#define CS42L43_DECIM_WNF_CF_MASK 0x00000070 +#define CS42L43_DECIM_WNF_CF_SHIFT 4 +#define CS42L43_DECIM_WNF_EN_MASK 0x00000008 +#define CS42L43_DECIM_WNF_EN_SHIFT 3 +#define CS42L43_DECIM_HPF_CF_MASK 0x00000006 +#define CS42L43_DECIM_HPF_CF_SHIFT 1 +#define CS42L43_DECIM_HPF_EN_MASK 0x00000001 +#define CS42L43_DECIM_HPF_EN_SHIFT 0 + +/* CS42L43_DMIC_PDM_CTRL */ +#define CS42L43_PDM2R_INV_MASK 0x00000020 +#define CS42L43_PDM2R_INV_SHIFT 5 +#define CS42L43_PDM2L_INV_MASK 0x00000010 +#define CS42L43_PDM2L_INV_SHIFT 4 +#define CS42L43_PDM1R_INV_MASK 0x00000008 +#define CS42L43_PDM1R_INV_SHIFT 3 +#define CS42L43_PDM1L_INV_MASK 0x00000004 +#define CS42L43_PDM1L_INV_SHIFT 2 + +/* CS42L43_DECIM_VOL_CTRL_CH1_CH2 */ +#define CS42L43_DECIM2_MUTE_MASK 0x80000000 +#define CS42L43_DECIM2_MUTE_SHIFT 31 +#define CS42L43_DECIM2_VOL_MASK 0x3FC00000 +#define CS42L43_DECIM2_VOL_SHIFT 22 +#define CS42L43_DECIM2_VD_RAMP_MASK 0x00380000 +#define CS42L43_DECIM2_VD_RAMP_SHIFT 19 +#define CS42L43_DECIM2_VI_RAMP_MASK 0x00070000 +#define CS42L43_DECIM2_VI_RAMP_SHIFT 16 +#define CS42L43_DECIM1_MUTE_MASK 0x00008000 +#define CS42L43_DECIM1_MUTE_SHIFT 15 +#define CS42L43_DECIM1_VOL_MASK 0x00003FC0 +#define CS42L43_DECIM1_VOL_SHIFT 6 +#define CS42L43_DECIM1_VD_RAMP_MASK 0x00000038 +#define CS42L43_DECIM1_VD_RAMP_SHIFT 3 +#define CS42L43_DECIM1_VI_RAMP_MASK 0x00000007 +#define CS42L43_DECIM1_VI_RAMP_SHIFT 0 + +/* CS42L43_DECIM_VOL_CTRL_CH3_CH4 */ +#define CS42L43_DECIM4_MUTE_MASK 0x80000000 +#define CS42L43_DECIM4_MUTE_SHIFT 31 +#define CS42L43_DECIM4_VOL_MASK 0x3FC00000 +#define CS42L43_DECIM4_VOL_SHIFT 22 +#define CS42L43_DECIM4_VD_RAMP_MASK 0x00380000 +#define CS42L43_DECIM4_VD_RAMP_SHIFT 19 +#define CS42L43_DECIM4_VI_RAMP_MASK 0x00070000 +#define CS42L43_DECIM4_VI_RAMP_SHIFT 16 +#define CS42L43_DECIM3_MUTE_MASK 0x00008000 +#define CS42L43_DECIM3_MUTE_SHIFT 15 +#define CS42L43_DECIM3_VOL_MASK 0x00003FC0 +#define CS42L43_DECIM3_VOL_SHIFT 6 +#define CS42L43_DECIM3_VD_RAMP_MASK 0x00000038 +#define CS42L43_DECIM3_VD_RAMP_SHIFT 3 +#define CS42L43_DECIM3_VI_RAMP_MASK 0x00000007 +#define CS42L43_DECIM3_VI_RAMP_SHIFT 0 + +/* CS42L43_DECIM_VOL_CTRL_UPDATE */ +#define CS42L43_DECIM4_VOL_UPDATE_MASK 0x00000008 +#define CS42L43_DECIM4_VOL_UPDATE_SHIFT 3 +#define CS42L43_DECIM3_VOL_UPDATE_MASK 0x00000004 +#define CS42L43_DECIM3_VOL_UPDATE_SHIFT 2 +#define CS42L43_DECIM2_VOL_UPDATE_MASK 0x00000002 +#define CS42L43_DECIM2_VOL_UPDATE_SHIFT 1 +#define CS42L43_DECIM1_VOL_UPDATE_MASK 0x00000001 +#define CS42L43_DECIM1_VOL_UPDATE_SHIFT 0 + +/* CS42L43_INTP_VOLUME_CTRL1..CS42L43_INTP_VOLUME_CTRL2 */ +#define CS42L43_AMP1_2_VU_MASK 0x00000200 +#define CS42L43_AMP1_2_VU_SHIFT 9 +#define CS42L43_AMP_MUTE_MASK 0x00000100 +#define CS42L43_AMP_MUTE_SHIFT 8 +#define CS42L43_AMP_VOL_MASK 0x000000FF +#define CS42L43_AMP_VOL_SHIFT 0 + +/* CS42L43_AMP1_2_VOL_RAMP */ +#define CS42L43_AMP1_2_VD_RAMP_MASK 0x00000070 +#define CS42L43_AMP1_2_VD_RAMP_SHIFT 4 +#define CS42L43_AMP1_2_VI_RAMP_MASK 0x00000007 +#define CS42L43_AMP1_2_VI_RAMP_SHIFT 0 + +/* CS42L43_ASP_CTRL */ +#define CS42L43_ASP_FSYNC_MODE_MASK 0x00000004 +#define CS42L43_ASP_FSYNC_MODE_SHIFT 2 +#define CS42L43_ASP_BCLK_EN_MASK 0x00000002 +#define CS42L43_ASP_BCLK_EN_SHIFT 1 +#define CS42L43_ASP_FSYNC_EN_MASK 0x00000001 +#define CS42L43_ASP_FSYNC_EN_SHIFT 0 + +/* CS42L43_ASP_FSYNC_CTRL1 */ +#define CS42L43_ASP_FSYNC_M_MASK 0x0007FFFF +#define CS42L43_ASP_FSYNC_M_SHIFT 0 + +/* CS42L43_ASP_FSYNC_CTRL3 */ +#define CS42L43_ASP_FSYNC_IN_INV_MASK 0x00000002 +#define CS42L43_ASP_FSYNC_IN_INV_SHIFT 1 +#define CS42L43_ASP_FSYNC_OUT_INV_MASK 0x00000001 +#define CS42L43_ASP_FSYNC_OUT_INV_SHIFT 0 + +/* CS42L43_ASP_FSYNC_CTRL4 */ +#define CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK 0x00001FFE +#define CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT 1 + +/* CS42L43_ASP_DATA_CTRL */ +#define CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK 0x00000008 +#define CS42L43_ASP_FSYNC_FRAME_START_PHASE_SHIFT 3 +#define CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK 0x00000007 +#define CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT 0 + +/* CS42L43_ASP_RX_EN */ +#define CS42L43_ASP_RX_CH6_EN_MASK 0x00000020 +#define CS42L43_ASP_RX_CH6_EN_SHIFT 5 +#define CS42L43_ASP_RX_CH5_EN_MASK 0x00000010 +#define CS42L43_ASP_RX_CH5_EN_SHIFT 4 +#define CS42L43_ASP_RX_CH4_EN_MASK 0x00000008 +#define CS42L43_ASP_RX_CH4_EN_SHIFT 3 +#define CS42L43_ASP_RX_CH3_EN_MASK 0x00000004 +#define CS42L43_ASP_RX_CH3_EN_SHIFT 2 +#define CS42L43_ASP_RX_CH2_EN_MASK 0x00000002 +#define CS42L43_ASP_RX_CH2_EN_SHIFT 1 +#define CS42L43_ASP_RX_CH1_EN_MASK 0x00000001 +#define CS42L43_ASP_RX_CH1_EN_SHIFT 0 + +/* CS42L43_ASP_TX_EN */ +#define CS42L43_ASP_TX_CH6_EN_MASK 0x00000020 +#define CS42L43_ASP_TX_CH6_EN_SHIFT 5 +#define CS42L43_ASP_TX_CH5_EN_MASK 0x00000010 +#define CS42L43_ASP_TX_CH5_EN_SHIFT 4 +#define CS42L43_ASP_TX_CH4_EN_MASK 0x00000008 +#define CS42L43_ASP_TX_CH4_EN_SHIFT 3 +#define CS42L43_ASP_TX_CH3_EN_MASK 0x00000004 +#define CS42L43_ASP_TX_CH3_EN_SHIFT 2 +#define CS42L43_ASP_TX_CH2_EN_MASK 0x00000002 +#define CS42L43_ASP_TX_CH2_EN_SHIFT 1 +#define CS42L43_ASP_TX_CH1_EN_MASK 0x00000001 +#define CS42L43_ASP_TX_CH1_EN_SHIFT 0 + +/* CS42L43_ASP_RX_CH1_CTRL..CS42L43_ASP_TX_CH6_CTRL */ +#define CS42L43_ASP_CH_WIDTH_MASK 0x001F0000 +#define CS42L43_ASP_CH_WIDTH_SHIFT 16 +#define CS42L43_ASP_CH_SLOT_MASK 0x00001FFE +#define CS42L43_ASP_CH_SLOT_SHIFT 1 +#define CS42L43_ASP_CH_SLOT_PHASE_MASK 0x00000001 +#define CS42L43_ASP_CH_SLOT_PHASE_SHIFT 0 + +/* CS42L43_ASPTX1_INPUT..CS42L43_AMP4MIX_INPUT4 */ +#define CS42L43_MIXER_VOL_MASK 0x00FE0000 +#define CS42L43_MIXER_VOL_SHIFT 17 +#define CS42L43_MIXER_SRC_MASK 0x000001FF +#define CS42L43_MIXER_SRC_SHIFT 0 + +/* CS42L43_ASRC_INT_ENABLES */ +#define CS42L43_ASRC_INT4_EN_MASK 0x00000008 +#define CS42L43_ASRC_INT4_EN_SHIFT 3 +#define CS42L43_ASRC_INT3_EN_MASK 0x00000004 +#define CS42L43_ASRC_INT3_EN_SHIFT 2 +#define CS42L43_ASRC_INT2_EN_MASK 0x00000002 +#define CS42L43_ASRC_INT2_EN_SHIFT 1 +#define CS42L43_ASRC_INT1_EN_MASK 0x00000001 +#define CS42L43_ASRC_INT1_EN_SHIFT 0 + +/* CS42L43_ASRC_DEC_ENABLES */ +#define CS42L43_ASRC_DEC4_EN_MASK 0x00000008 +#define CS42L43_ASRC_DEC4_EN_SHIFT 3 +#define CS42L43_ASRC_DEC3_EN_MASK 0x00000004 +#define CS42L43_ASRC_DEC3_EN_SHIFT 2 +#define CS42L43_ASRC_DEC2_EN_MASK 0x00000002 +#define CS42L43_ASRC_DEC2_EN_SHIFT 1 +#define CS42L43_ASRC_DEC1_EN_MASK 0x00000001 +#define CS42L43_ASRC_DEC1_EN_SHIFT 0 + +/* CS42L43_PDNCNTL */ +#define CS42L43_RING_SENSE_EN_MASK 0x00000002 +#define CS42L43_RING_SENSE_EN_SHIFT 1 + +/* CS42L43_RINGSENSE_DEB_CTRL */ +#define CS42L43_RINGSENSE_INV_MASK 0x00000080 +#define CS42L43_RINGSENSE_INV_SHIFT 7 +#define CS42L43_RINGSENSE_PULLUP_PDNB_MASK 0x00000040 +#define CS42L43_RINGSENSE_PULLUP_PDNB_SHIFT 6 +#define CS42L43_RINGSENSE_FALLING_DB_TIME_MASK 0x00000038 +#define CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT 3 +#define CS42L43_RINGSENSE_RISING_DB_TIME_MASK 0x00000007 +#define CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT 0 + +/* CS42L43_TIPSENSE_DEB_CTRL */ +#define CS42L43_TIPSENSE_INV_MASK 0x00000080 +#define CS42L43_TIPSENSE_INV_SHIFT 7 +#define CS42L43_TIPSENSE_FALLING_DB_TIME_MASK 0x00000038 +#define CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT 3 +#define CS42L43_TIPSENSE_RISING_DB_TIME_MASK 0x00000007 +#define CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT 0 + +/* CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS */ +#define CS42L43_TIPSENSE_UNPLUG_DB_STS_MASK 0x00000008 +#define CS42L43_TIPSENSE_UNPLUG_DB_STS_SHIFT 3 +#define CS42L43_TIPSENSE_PLUG_DB_STS_MASK 0x00000004 +#define CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT 2 +#define CS42L43_RINGSENSE_UNPLUG_DB_STS_MASK 0x00000002 +#define CS42L43_RINGSENSE_UNPLUG_DB_STS_SHIFT 1 +#define CS42L43_RINGSENSE_PLUG_DB_STS_MASK 0x00000001 +#define CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT 0 + +/* CS42L43_HS2 */ +#define CS42L43_HS_CLAMP_DISABLE_MASK 0x10000000 +#define CS42L43_HS_CLAMP_DISABLE_SHIFT 28 +#define CS42L43_HSBIAS_RAMP_MASK 0x0C000000 +#define CS42L43_HSBIAS_RAMP_SHIFT 26 +#define CS42L43_HSDET_MODE_MASK 0x00018000 +#define CS42L43_HSDET_MODE_SHIFT 15 +#define CS42L43_HSDET_MANUAL_MODE_MASK 0x00006000 +#define CS42L43_HSDET_MANUAL_MODE_SHIFT 13 +#define CS42L43_AUTO_HSDET_TIME_MASK 0x00000700 +#define CS42L43_AUTO_HSDET_TIME_SHIFT 8 +#define CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK 0x00000080 +#define CS42L43_AMP3_4_GNDREF_HS3_SEL_SHIFT 7 +#define CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK 0x00000040 +#define CS42L43_AMP3_4_GNDREF_HS4_SEL_SHIFT 6 +#define CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK 0x00000020 +#define CS42L43_HSBIAS_GNDREF_HS3_SEL_SHIFT 5 +#define CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK 0x00000010 +#define CS42L43_HSBIAS_GNDREF_HS4_SEL_SHIFT 4 +#define CS42L43_HSBIAS_OUT_HS3_SEL_MASK 0x00000008 +#define CS42L43_HSBIAS_OUT_HS3_SEL_SHIFT 3 +#define CS42L43_HSBIAS_OUT_HS4_SEL_MASK 0x00000004 +#define CS42L43_HSBIAS_OUT_HS4_SEL_SHIFT 2 +#define CS42L43_HSGND_HS3_SEL_MASK 0x00000002 +#define CS42L43_HSGND_HS3_SEL_SHIFT 1 +#define CS42L43_HSGND_HS4_SEL_MASK 0x00000001 +#define CS42L43_HSGND_HS4_SEL_SHIFT 0 + +/* CS42L43_HS_STAT */ +#define CS42L43_HSDET_TYPE_STS_MASK 0x00000007 +#define CS42L43_HSDET_TYPE_STS_SHIFT 0 + +/* CS42L43_MCU_SW_INTERRUPT */ +#define CS42L43_CONTROL_IND_MASK 0x00000004 +#define CS42L43_CONTROL_IND_SHIFT 2 +#define CS42L43_CONFIGS_IND_MASK 0x00000002 +#define CS42L43_CONFIGS_IND_SHIFT 1 +#define CS42L43_PATCH_IND_MASK 0x00000001 +#define CS42L43_PATCH_IND_SHIFT 0 + +/* CS42L43_STEREO_MIC_CTRL */ +#define CS42L43_HS2_BIAS_SENSE_EN_MASK 0x00000020 +#define CS42L43_HS2_BIAS_SENSE_EN_SHIFT 5 +#define CS42L43_HS1_BIAS_SENSE_EN_MASK 0x00000010 +#define CS42L43_HS1_BIAS_SENSE_EN_SHIFT 4 +#define CS42L43_HS2_BIAS_EN_MASK 0x00000008 +#define CS42L43_HS2_BIAS_EN_SHIFT 3 +#define CS42L43_HS1_BIAS_EN_MASK 0x00000004 +#define CS42L43_HS1_BIAS_EN_SHIFT 2 +#define CS42L43_JACK_STEREO_CONFIG_MASK 0x00000003 +#define CS42L43_JACK_STEREO_CONFIG_SHIFT 0 + +/* CS42L43_STEREO_MIC_CLAMP_CTRL */ +#define CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK 0x00000002 +#define CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_SHIFT 1 +#define CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK 0x00000001 +#define CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_SHIFT 0 + +/* CS42L43_BLOCK_EN2 */ +#define CS42L43_SPI_MSTR_EN_MASK 0x00000001 +#define CS42L43_SPI_MSTR_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN3 */ +#define CS42L43_PDM2_DIN_R_EN_MASK 0x00000020 +#define CS42L43_PDM2_DIN_R_EN_SHIFT 5 +#define CS42L43_PDM2_DIN_L_EN_MASK 0x00000010 +#define CS42L43_PDM2_DIN_L_EN_SHIFT 4 +#define CS42L43_PDM1_DIN_R_EN_MASK 0x00000008 +#define CS42L43_PDM1_DIN_R_EN_SHIFT 3 +#define CS42L43_PDM1_DIN_L_EN_MASK 0x00000004 +#define CS42L43_PDM1_DIN_L_EN_SHIFT 2 +#define CS42L43_ADC2_EN_MASK 0x00000002 +#define CS42L43_ADC2_EN_SHIFT 1 +#define CS42L43_ADC1_EN_MASK 0x00000001 +#define CS42L43_ADC1_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN4 */ +#define CS42L43_ASRC_DEC_BANK_EN_MASK 0x00000002 +#define CS42L43_ASRC_DEC_BANK_EN_SHIFT 1 +#define CS42L43_ASRC_INT_BANK_EN_MASK 0x00000001 +#define CS42L43_ASRC_INT_BANK_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN5 */ +#define CS42L43_ISRC2_BANK_EN_MASK 0x00000002 +#define CS42L43_ISRC2_BANK_EN_SHIFT 1 +#define CS42L43_ISRC1_BANK_EN_MASK 0x00000001 +#define CS42L43_ISRC1_BANK_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN6 */ +#define CS42L43_MIXER_EN_MASK 0x00000001 +#define CS42L43_MIXER_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN7 */ +#define CS42L43_EQ_EN_MASK 0x00000001 +#define CS42L43_EQ_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN8 */ +#define CS42L43_HP_EN_MASK 0x00000001 +#define CS42L43_HP_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN9 */ +#define CS42L43_TONE_EN_MASK 0x00000001 +#define CS42L43_TONE_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN10 */ +#define CS42L43_AMP2_EN_MASK 0x00000002 +#define CS42L43_AMP2_EN_SHIFT 1 +#define CS42L43_AMP1_EN_MASK 0x00000001 +#define CS42L43_AMP1_EN_SHIFT 0 + +/* CS42L43_BLOCK_EN11 */ +#define CS42L43_SPDIF_EN_MASK 0x00000001 +#define CS42L43_SPDIF_EN_SHIFT 0 + +/* CS42L43_TONE_CH1_CTRL..CS42L43_TONE_CH2_CTRL */ +#define CS42L43_TONE_FREQ_MASK 0x00000070 +#define CS42L43_TONE_FREQ_SHIFT 4 +#define CS42L43_TONE_SEL_MASK 0x0000000F +#define CS42L43_TONE_SEL_SHIFT 0 + +/* CS42L43_MIC_DETECT_CONTROL_1 */ +#define CS42L43_BUTTON_DETECT_MODE_MASK 0x00000018 +#define CS42L43_BUTTON_DETECT_MODE_SHIFT 3 +#define CS42L43_HSBIAS_MODE_MASK 0x00000006 +#define CS42L43_HSBIAS_MODE_SHIFT 1 +#define CS42L43_MIC_LVL_DET_DISABLE_MASK 0x00000001 +#define CS42L43_MIC_LVL_DET_DISABLE_SHIFT 0 + +/* CS42L43_DETECT_STATUS_1 */ +#define CS42L43_HSDET_DC_STS_MASK 0x01FF0000 +#define CS42L43_HSDET_DC_STS_SHIFT 16 +#define CS42L43_JACKDET_STS_MASK 0x00000080 +#define CS42L43_JACKDET_STS_SHIFT 7 +#define CS42L43_HSBIAS_CLAMP_STS_MASK 0x00000040 +#define CS42L43_HSBIAS_CLAMP_STS_SHIFT 6 + +/* CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL */ +#define CS42L43_JACKDET_MODE_MASK 0xC0000000 +#define CS42L43_JACKDET_MODE_SHIFT 30 +#define CS42L43_JACKDET_INV_MASK 0x20000000 +#define CS42L43_JACKDET_INV_SHIFT 29 +#define CS42L43_JACKDET_DB_TIME_MASK 0x03000000 +#define CS42L43_JACKDET_DB_TIME_SHIFT 24 +#define CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK 0x00800000 +#define CS42L43_S0_AUTO_ADCMUTE_DISABLE_SHIFT 23 +#define CS42L43_HSBIAS_SENSE_EN_MASK 0x00000080 +#define CS42L43_HSBIAS_SENSE_EN_SHIFT 7 +#define CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK 0x00000040 +#define CS42L43_AUTO_HSBIAS_CLAMP_EN_SHIFT 6 +#define CS42L43_JACKDET_SENSE_EN_MASK 0x00000020 +#define CS42L43_JACKDET_SENSE_EN_SHIFT 5 +#define CS42L43_HSBIAS_SENSE_TRIP_MASK 0x00000007 +#define CS42L43_HSBIAS_SENSE_TRIP_SHIFT 0 + +/* CS42L43_MIC_DETECT_CONTROL_ANDROID */ +#define CS42L43_HSDET_LVL_COMBWIDTH_MASK 0xC0000000 +#define CS42L43_HSDET_LVL_COMBWIDTH_SHIFT 30 +#define CS42L43_HSDET_LVL2_THRESH_MASK 0x01FF0000 +#define CS42L43_HSDET_LVL2_THRESH_SHIFT 16 +#define CS42L43_HSDET_LVL1_THRESH_MASK 0x000001FF +#define CS42L43_HSDET_LVL1_THRESH_SHIFT 0 + +/* CS42L43_ISRC1_CTRL..CS42L43_ISRC2_CTRL */ +#define CS42L43_ISRC_INT2_EN_MASK 0x00000200 +#define CS42L43_ISRC_INT2_EN_SHIFT 9 +#define CS42L43_ISRC_INT1_EN_MASK 0x00000100 +#define CS42L43_ISRC_INT1_EN_SHIFT 8 +#define CS42L43_ISRC_DEC2_EN_MASK 0x00000002 +#define CS42L43_ISRC_DEC2_EN_SHIFT 1 +#define CS42L43_ISRC_DEC1_EN_MASK 0x00000001 +#define CS42L43_ISRC_DEC1_EN_SHIFT 0 + +/* CS42L43_CTRL_REG */ +#define CS42L43_PLL_MODE_BYPASS_500_MASK 0x00000004 +#define CS42L43_PLL_MODE_BYPASS_500_SHIFT 2 +#define CS42L43_PLL_MODE_BYPASS_1029_MASK 0x00000002 +#define CS42L43_PLL_MODE_BYPASS_1029_SHIFT 1 +#define CS42L43_PLL_EN_MASK 0x00000001 +#define CS42L43_PLL_EN_SHIFT 0 + +/* CS42L43_FDIV_FRAC */ +#define CS42L43_PLL_DIV_INT_MASK 0xFF000000 +#define CS42L43_PLL_DIV_INT_SHIFT 24 +#define CS42L43_PLL_DIV_FRAC_BYTE2_MASK 0x00FF0000 +#define CS42L43_PLL_DIV_FRAC_BYTE2_SHIFT 16 +#define CS42L43_PLL_DIV_FRAC_BYTE1_MASK 0x0000FF00 +#define CS42L43_PLL_DIV_FRAC_BYTE1_SHIFT 8 +#define CS42L43_PLL_DIV_FRAC_BYTE0_MASK 0x000000FF +#define CS42L43_PLL_DIV_FRAC_BYTE0_SHIFT 0 + +/* CS42L43_CAL_RATIO */ +#define CS42L43_PLL_CAL_RATIO_MASK 0x000000FF +#define CS42L43_PLL_CAL_RATIO_SHIFT 0 + +/* CS42L43_SPI_CLK_CONFIG1 */ +#define CS42L43_SCLK_DIV_MASK 0x0000000F +#define CS42L43_SCLK_DIV_SHIFT 0 + +/* CS42L43_SPI_CONFIG1 */ +#define CS42L43_SPI_SS_IDLE_DUR_MASK 0x0F000000 +#define CS42L43_SPI_SS_IDLE_DUR_SHIFT 24 +#define CS42L43_SPI_SS_DELAY_DUR_MASK 0x000F0000 +#define CS42L43_SPI_SS_DELAY_DUR_SHIFT 16 +#define CS42L43_SPI_THREE_WIRE_MASK 0x00000100 +#define CS42L43_SPI_THREE_WIRE_SHIFT 8 +#define CS42L43_SPI_DPHA_MASK 0x00000040 +#define CS42L43_SPI_DPHA_SHIFT 6 +#define CS42L43_SPI_CPHA_MASK 0x00000020 +#define CS42L43_SPI_CPHA_SHIFT 5 +#define CS42L43_SPI_CPOL_MASK 0x00000010 +#define CS42L43_SPI_CPOL_SHIFT 4 +#define CS42L43_SPI_SS_SEL_MASK 0x00000007 +#define CS42L43_SPI_SS_SEL_SHIFT 0 + +/* CS42L43_SPI_CONFIG2 */ +#define CS42L43_SPI_SS_FRC_MASK 0x00000001 +#define CS42L43_SPI_SS_FRC_SHIFT 0 + +/* CS42L43_SPI_CONFIG3 */ +#define CS42L43_SPI_WDT_ENA_MASK 0x00000001 +#define CS42L43_SPI_WDT_ENA_SHIFT 0 + +/* CS42L43_SPI_CONFIG4 */ +#define CS42L43_SPI_STALL_ENA_MASK 0x00010000 +#define CS42L43_SPI_STALL_ENA_SHIFT 16 + +/* CS42L43_SPI_STATUS1 */ +#define CS42L43_SPI_ABORT_STS_MASK 0x00000002 +#define CS42L43_SPI_ABORT_STS_SHIFT 1 +#define CS42L43_SPI_DONE_STS_MASK 0x00000001 +#define CS42L43_SPI_DONE_STS_SHIFT 0 + +/* CS42L43_SPI_STATUS2 */ +#define CS42L43_SPI_RX_DONE_STS_MASK 0x00000010 +#define CS42L43_SPI_RX_DONE_STS_SHIFT 4 +#define CS42L43_SPI_TX_DONE_STS_MASK 0x00000001 +#define CS42L43_SPI_TX_DONE_STS_SHIFT 0 + +/* CS42L43_TRAN_CONFIG1 */ +#define CS42L43_SPI_START_MASK 0x00000001 +#define CS42L43_SPI_START_SHIFT 0 + +/* CS42L43_TRAN_CONFIG2 */ +#define CS42L43_SPI_ABORT_MASK 0x00000001 +#define CS42L43_SPI_ABORT_SHIFT 0 + +/* CS42L43_TRAN_CONFIG3 */ +#define CS42L43_SPI_WORD_SIZE_MASK 0x00070000 +#define CS42L43_SPI_WORD_SIZE_SHIFT 16 +#define CS42L43_SPI_CMD_MASK 0x00000003 +#define CS42L43_SPI_CMD_SHIFT 0 + +/* CS42L43_TRAN_CONFIG4 */ +#define CS42L43_SPI_TX_LENGTH_MASK 0x0000FFFF +#define CS42L43_SPI_TX_LENGTH_SHIFT 0 + +/* CS42L43_TRAN_CONFIG5 */ +#define CS42L43_SPI_RX_LENGTH_MASK 0x0000FFFF +#define CS42L43_SPI_RX_LENGTH_SHIFT 0 + +/* CS42L43_TRAN_CONFIG6 */ +#define CS42L43_SPI_TX_BLOCK_LENGTH_MASK 0x0000000F +#define CS42L43_SPI_TX_BLOCK_LENGTH_SHIFT 0 + +/* CS42L43_TRAN_CONFIG7 */ +#define CS42L43_SPI_RX_BLOCK_LENGTH_MASK 0x0000000F +#define CS42L43_SPI_RX_BLOCK_LENGTH_SHIFT 0 + +/* CS42L43_TRAN_CONFIG8 */ +#define CS42L43_SPI_RX_DONE_MASK 0x00000010 +#define CS42L43_SPI_RX_DONE_SHIFT 4 +#define CS42L43_SPI_TX_DONE_MASK 0x00000001 +#define CS42L43_SPI_TX_DONE_SHIFT 0 + +/* CS42L43_TRAN_STATUS1 */ +#define CS42L43_SPI_BUSY_STS_MASK 0x00000100 +#define CS42L43_SPI_BUSY_STS_SHIFT 8 +#define CS42L43_SPI_RX_REQUEST_MASK 0x00000010 +#define CS42L43_SPI_RX_REQUEST_SHIFT 4 +#define CS42L43_SPI_TX_REQUEST_MASK 0x00000001 +#define CS42L43_SPI_TX_REQUEST_SHIFT 0 + +/* CS42L43_TRAN_STATUS2 */ +#define CS42L43_SPI_TX_BYTE_COUNT_MASK 0x0000FFFF +#define CS42L43_SPI_TX_BYTE_COUNT_SHIFT 0 + +/* CS42L43_TRAN_STATUS3 */ +#define CS42L43_SPI_RX_BYTE_COUNT_MASK 0x0000FFFF +#define CS42L43_SPI_RX_BYTE_COUNT_SHIFT 0 + +/* CS42L43_TX_DATA */ +#define CS42L43_SPI_TX_DATA_MASK 0xFFFFFFFF +#define CS42L43_SPI_TX_DATA_SHIFT 0 + +/* CS42L43_RX_DATA */ +#define CS42L43_SPI_RX_DATA_MASK 0xFFFFFFFF +#define CS42L43_SPI_RX_DATA_SHIFT 0 + +/* CS42L43_DACCNFG1 */ +#define CS42L43_HP_MSTR_VOL_CTRL_EN_MASK 0x00000008 +#define CS42L43_HP_MSTR_VOL_CTRL_EN_SHIFT 3 +#define CS42L43_AMP4_INV_MASK 0x00000002 +#define CS42L43_AMP4_INV_SHIFT 1 +#define CS42L43_AMP3_INV_MASK 0x00000001 +#define CS42L43_AMP3_INV_SHIFT 0 + +/* CS42L43_DACCNFG2 */ +#define CS42L43_HP_AUTO_CLAMP_DISABLE_MASK 0x00000002 +#define CS42L43_HP_AUTO_CLAMP_DISABLE_SHIFT 1 +#define CS42L43_HP_HPF_EN_MASK 0x00000001 +#define CS42L43_HP_HPF_EN_SHIFT 0 + +/* CS42L43_HPPATHVOL */ +#define CS42L43_AMP4_PATH_VOL_MASK 0x01FF0000 +#define CS42L43_AMP4_PATH_VOL_SHIFT 16 +#define CS42L43_AMP3_PATH_VOL_MASK 0x000001FF +#define CS42L43_AMP3_PATH_VOL_SHIFT 0 + +/* CS42L43_PGAVOL */ +#define CS42L43_HP_PATH_VOL_RAMP_MASK 0x0003C000 +#define CS42L43_HP_PATH_VOL_RAMP_SHIFT 14 +#define CS42L43_HP_PATH_VOL_ZC_MASK 0x00002000 +#define CS42L43_HP_PATH_VOL_ZC_SHIFT 13 +#define CS42L43_HP_PATH_VOL_SFT_MASK 0x00001000 +#define CS42L43_HP_PATH_VOL_SFT_SHIFT 12 +#define CS42L43_HP_DIG_VOL_RAMP_MASK 0x00000F00 +#define CS42L43_HP_DIG_VOL_RAMP_SHIFT 8 +#define CS42L43_HP_ANA_VOL_RAMP_MASK 0x0000000F +#define CS42L43_HP_ANA_VOL_RAMP_SHIFT 0 + +/* CS42L43_LOADDETRESULTS */ +#define CS42L43_AMP3_RES_DET_MASK 0x00000003 +#define CS42L43_AMP3_RES_DET_SHIFT 0 + +/* CS42L43_LOADDETENA */ +#define CS42L43_HPLOAD_DET_EN_MASK 0x00000001 +#define CS42L43_HPLOAD_DET_EN_SHIFT 0 + +/* CS42L43_CTRL */ +#define CS42L43_ADPTPWR_MODE_MASK 0x00000007 +#define CS42L43_ADPTPWR_MODE_SHIFT 0 + +/* CS42L43_COEFF_RD_WR0 */ +#define CS42L43_WRITE_MODE_MASK 0x00000002 +#define CS42L43_WRITE_MODE_SHIFT 1 + +/* CS42L43_INIT_DONE0 */ +#define CS42L43_INITIALIZE_DONE_MASK 0x00000001 +#define CS42L43_INITIALIZE_DONE_SHIFT 0 + +/* CS42L43_START_EQZ0 */ +#define CS42L43_START_FILTER_MASK 0x00000001 +#define CS42L43_START_FILTER_SHIFT 0 + +/* CS42L43_MUTE_EQ_IN0 */ +#define CS42L43_MUTE_EQ_CH2_MASK 0x00000002 +#define CS42L43_MUTE_EQ_CH2_SHIFT 1 +#define CS42L43_MUTE_EQ_CH1_MASK 0x00000001 +#define CS42L43_MUTE_EQ_CH1_SHIFT 0 + +/* CS42L43_PLL_INT */ +#define CS42L43_PLL_LOST_LOCK_INT_MASK 0x00000002 +#define CS42L43_PLL_LOST_LOCK_INT_SHIFT 1 +#define CS42L43_PLL_READY_INT_MASK 0x00000001 +#define CS42L43_PLL_READY_INT_SHIFT 0 + +/* CS42L43_SOFT_INT */ +#define CS42L43_CONTROL_APPLIED_INT_MASK 0x00000010 +#define CS42L43_CONTROL_APPLIED_INT_SHIFT 4 +#define CS42L43_CONTROL_WARN_INT_MASK 0x00000008 +#define CS42L43_CONTROL_WARN_INT_SHIFT 3 +#define CS42L43_PATCH_WARN_INT_MASK 0x00000002 +#define CS42L43_PATCH_WARN_INT_SHIFT 1 +#define CS42L43_PATCH_APPLIED_INT_MASK 0x00000001 +#define CS42L43_PATCH_APPLIED_INT_SHIFT 0 + +/* CS42L43_MSM_INT */ +#define CS42L43_HP_STARTUP_DONE_INT_MASK 0x00000800 +#define CS42L43_HP_STARTUP_DONE_INT_SHIFT 11 +#define CS42L43_HP_SHUTDOWN_DONE_INT_MASK 0x00000400 +#define CS42L43_HP_SHUTDOWN_DONE_INT_SHIFT 10 +#define CS42L43_HSDET_DONE_INT_MASK 0x00000200 +#define CS42L43_HSDET_DONE_INT_SHIFT 9 +#define CS42L43_TIPSENSE_UNPLUG_DB_INT_MASK 0x00000080 +#define CS42L43_TIPSENSE_UNPLUG_DB_INT_SHIFT 7 +#define CS42L43_TIPSENSE_PLUG_DB_INT_MASK 0x00000040 +#define CS42L43_TIPSENSE_PLUG_DB_INT_SHIFT 6 +#define CS42L43_RINGSENSE_UNPLUG_DB_INT_MASK 0x00000020 +#define CS42L43_RINGSENSE_UNPLUG_DB_INT_SHIFT 5 +#define CS42L43_RINGSENSE_PLUG_DB_INT_MASK 0x00000010 +#define CS42L43_RINGSENSE_PLUG_DB_INT_SHIFT 4 +#define CS42L43_TIPSENSE_UNPLUG_PDET_INT_MASK 0x00000008 +#define CS42L43_TIPSENSE_UNPLUG_PDET_INT_SHIFT 3 +#define CS42L43_TIPSENSE_PLUG_PDET_INT_MASK 0x00000004 +#define CS42L43_TIPSENSE_PLUG_PDET_INT_SHIFT 2 +#define CS42L43_RINGSENSE_UNPLUG_PDET_INT_MASK 0x00000002 +#define CS42L43_RINGSENSE_UNPLUG_PDET_INT_SHIFT 1 +#define CS42L43_RINGSENSE_PLUG_PDET_INT_MASK 0x00000001 +#define CS42L43_RINGSENSE_PLUG_PDET_INT_SHIFT 0 + +/* CS42L43_ACC_DET_INT */ +#define CS42L43_HS2_BIAS_SENSE_INT_MASK 0x00000800 +#define CS42L43_HS2_BIAS_SENSE_INT_SHIFT 11 +#define CS42L43_HS1_BIAS_SENSE_INT_MASK 0x00000400 +#define CS42L43_HS1_BIAS_SENSE_INT_SHIFT 10 +#define CS42L43_DC_DETECT1_FALSE_INT_MASK 0x00000080 +#define CS42L43_DC_DETECT1_FALSE_INT_SHIFT 7 +#define CS42L43_DC_DETECT1_TRUE_INT_MASK 0x00000040 +#define CS42L43_DC_DETECT1_TRUE_INT_SHIFT 6 +#define CS42L43_HSBIAS_CLAMPED_INT_MASK 0x00000008 +#define CS42L43_HSBIAS_CLAMPED_INT_SHIFT 3 +#define CS42L43_HS3_4_BIAS_SENSE_INT_MASK 0x00000001 +#define CS42L43_HS3_4_BIAS_SENSE_INT_SHIFT 0 + +/* CS42L43_SPI_MSTR_INT */ +#define CS42L43_IRQ_SPI_STALLING_INT_MASK 0x00000004 +#define CS42L43_IRQ_SPI_STALLING_INT_SHIFT 2 +#define CS42L43_IRQ_SPI_STS_INT_MASK 0x00000002 +#define CS42L43_IRQ_SPI_STS_INT_SHIFT 1 +#define CS42L43_IRQ_SPI_BLOCK_INT_MASK 0x00000001 +#define CS42L43_IRQ_SPI_BLOCK_INT_SHIFT 0 + +/* CS42L43_SW_TO_SPI_BRIDGE_INT */ +#define CS42L43_SW2SPI_BUF_OVF_UDF_INT_MASK 0x00000001 +#define CS42L43_SW2SPI_BUF_OVF_UDF_INT_SHIFT 0 + +/* CS42L43_CLASS_D_AMP_INT */ +#define CS42L43_AMP2_CLK_STOP_FAULT_INT_MASK 0x00002000 +#define CS42L43_AMP2_CLK_STOP_FAULT_INT_SHIFT 13 +#define CS42L43_AMP1_CLK_STOP_FAULT_INT_MASK 0x00001000 +#define CS42L43_AMP1_CLK_STOP_FAULT_INT_SHIFT 12 +#define CS42L43_AMP2_VDDSPK_FAULT_INT_MASK 0x00000800 +#define CS42L43_AMP2_VDDSPK_FAULT_INT_SHIFT 11 +#define CS42L43_AMP1_VDDSPK_FAULT_INT_MASK 0x00000400 +#define CS42L43_AMP1_VDDSPK_FAULT_INT_SHIFT 10 +#define CS42L43_AMP2_SHUTDOWN_DONE_INT_MASK 0x00000200 +#define CS42L43_AMP2_SHUTDOWN_DONE_INT_SHIFT 9 +#define CS42L43_AMP1_SHUTDOWN_DONE_INT_MASK 0x00000100 +#define CS42L43_AMP1_SHUTDOWN_DONE_INT_SHIFT 8 +#define CS42L43_AMP2_STARTUP_DONE_INT_MASK 0x00000080 +#define CS42L43_AMP2_STARTUP_DONE_INT_SHIFT 7 +#define CS42L43_AMP1_STARTUP_DONE_INT_MASK 0x00000040 +#define CS42L43_AMP1_STARTUP_DONE_INT_SHIFT 6 +#define CS42L43_AMP2_THERM_SHDN_INT_MASK 0x00000020 +#define CS42L43_AMP2_THERM_SHDN_INT_SHIFT 5 +#define CS42L43_AMP1_THERM_SHDN_INT_MASK 0x00000010 +#define CS42L43_AMP1_THERM_SHDN_INT_SHIFT 4 +#define CS42L43_AMP2_THERM_WARN_INT_MASK 0x00000008 +#define CS42L43_AMP2_THERM_WARN_INT_SHIFT 3 +#define CS42L43_AMP1_THERM_WARN_INT_MASK 0x00000004 +#define CS42L43_AMP1_THERM_WARN_INT_SHIFT 2 +#define CS42L43_AMP2_SCDET_INT_MASK 0x00000002 +#define CS42L43_AMP2_SCDET_INT_SHIFT 1 +#define CS42L43_AMP1_SCDET_INT_MASK 0x00000001 +#define CS42L43_AMP1_SCDET_INT_SHIFT 0 + +/* CS42L43_GPIO_INT */ +#define CS42L43_GPIO3_FALL_INT_MASK 0x00000020 +#define CS42L43_GPIO3_FALL_INT_SHIFT 5 +#define CS42L43_GPIO3_RISE_INT_MASK 0x00000010 +#define CS42L43_GPIO3_RISE_INT_SHIFT 4 +#define CS42L43_GPIO2_FALL_INT_MASK 0x00000008 +#define CS42L43_GPIO2_FALL_INT_SHIFT 3 +#define CS42L43_GPIO2_RISE_INT_MASK 0x00000004 +#define CS42L43_GPIO2_RISE_INT_SHIFT 2 +#define CS42L43_GPIO1_FALL_INT_MASK 0x00000002 +#define CS42L43_GPIO1_FALL_INT_SHIFT 1 +#define CS42L43_GPIO1_RISE_INT_MASK 0x00000001 +#define CS42L43_GPIO1_RISE_INT_SHIFT 0 + +/* CS42L43_HPOUT_INT */ +#define CS42L43_HP_ILIMIT_INT_MASK 0x00000002 +#define CS42L43_HP_ILIMIT_INT_SHIFT 1 +#define CS42L43_HP_LOADDET_DONE_INT_MASK 0x00000001 +#define CS42L43_HP_LOADDET_DONE_INT_SHIFT 0 + +/* CS42L43_BOOT_CONTROL */ +#define CS42L43_LOCK_HW_STS_MASK 0x00000002 +#define CS42L43_LOCK_HW_STS_SHIFT 1 + +/* CS42L43_BLOCK_EN */ +#define CS42L43_MCU_EN_MASK 0x00000001 +#define CS42L43_MCU_EN_SHIFT 0 + +/* CS42L43_SHUTTER_CONTROL */ +#define CS42L43_STATUS_SPK_SHUTTER_MUTE_MASK 0x00008000 +#define CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT 15 +#define CS42L43_SPK_SHUTTER_CFG_MASK 0x00000F00 +#define CS42L43_SPK_SHUTTER_CFG_SHIFT 8 +#define CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK 0x00000080 +#define CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT 7 +#define CS42L43_MIC_SHUTTER_CFG_MASK 0x0000000F +#define CS42L43_MIC_SHUTTER_CFG_SHIFT 0 + +/* CS42L43_MCU_SW_REV */ +#define CS42L43_BIOS_SUBMINOR_REV_MASK 0xFF000000 +#define CS42L43_BIOS_SUBMINOR_REV_SHIFT 24 +#define CS42L43_BIOS_MINOR_REV_MASK 0x00F00000 +#define CS42L43_BIOS_MINOR_REV_SHIFT 20 +#define CS42L43_BIOS_MAJOR_REV_MASK 0x000F0000 +#define CS42L43_BIOS_MAJOR_REV_SHIFT 16 +#define CS42L43_FW_SUBMINOR_REV_MASK 0x0000FF00 +#define CS42L43_FW_SUBMINOR_REV_SHIFT 8 +#define CS42L43_FW_MINOR_REV_MASK 0x000000F0 +#define CS42L43_FW_MINOR_REV_SHIFT 4 +#define CS42L43_FW_MAJOR_REV_MASK 0x0000000F +#define CS42L43_FW_MAJOR_REV_SHIFT 0 + +/* CS42L43_NEED_CONFIGS */ +#define CS42L43_FW_PATCH_NEED_CFG_MASK 0x80000000 +#define CS42L43_FW_PATCH_NEED_CFG_SHIFT 31 + +/* CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION */ +#define CS42L43_FW_MM_CTRL_MCU_SEL_MASK 0x00000001 +#define CS42L43_FW_MM_CTRL_MCU_SEL_SHIFT 0 + +/* CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG */ +#define CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL 0xF05AA50F + +#endif /* CS42L43_CORE_REGS_H */ diff --git a/include/linux/mfd/cs42l43.h b/include/linux/mfd/cs42l43.h new file mode 100644 index 000000000000..cf8263aab41b --- /dev/null +++ b/include/linux/mfd/cs42l43.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS42L43 core driver external data + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CS42L43_CORE_EXT_H +#define CS42L43_CORE_EXT_H + +#define CS42L43_N_SUPPLIES 3 + +enum cs42l43_irq_numbers { + CS42L43_PLL_LOST_LOCK, + CS42L43_PLL_READY, + + CS42L43_HP_STARTUP_DONE, + CS42L43_HP_SHUTDOWN_DONE, + CS42L43_HSDET_DONE, + CS42L43_TIPSENSE_UNPLUG_DB, + CS42L43_TIPSENSE_PLUG_DB, + CS42L43_RINGSENSE_UNPLUG_DB, + CS42L43_RINGSENSE_PLUG_DB, + CS42L43_TIPSENSE_UNPLUG_PDET, + CS42L43_TIPSENSE_PLUG_PDET, + CS42L43_RINGSENSE_UNPLUG_PDET, + CS42L43_RINGSENSE_PLUG_PDET, + + CS42L43_HS2_BIAS_SENSE, + CS42L43_HS1_BIAS_SENSE, + CS42L43_DC_DETECT1_FALSE, + CS42L43_DC_DETECT1_TRUE, + CS42L43_HSBIAS_CLAMPED, + CS42L43_HS3_4_BIAS_SENSE, + + CS42L43_AMP2_CLK_STOP_FAULT, + CS42L43_AMP1_CLK_STOP_FAULT, + CS42L43_AMP2_VDDSPK_FAULT, + CS42L43_AMP1_VDDSPK_FAULT, + CS42L43_AMP2_SHUTDOWN_DONE, + CS42L43_AMP1_SHUTDOWN_DONE, + CS42L43_AMP2_STARTUP_DONE, + CS42L43_AMP1_STARTUP_DONE, + CS42L43_AMP2_THERM_SHDN, + CS42L43_AMP1_THERM_SHDN, + CS42L43_AMP2_THERM_WARN, + CS42L43_AMP1_THERM_WARN, + CS42L43_AMP2_SCDET, + CS42L43_AMP1_SCDET, + + CS42L43_GPIO3_FALL, + CS42L43_GPIO3_RISE, + CS42L43_GPIO2_FALL, + CS42L43_GPIO2_RISE, + CS42L43_GPIO1_FALL, + CS42L43_GPIO1_RISE, + + CS42L43_HP_ILIMIT, + CS42L43_HP_LOADDET_DONE, +}; + +struct cs42l43 { + struct device *dev; + struct regmap *regmap; + struct sdw_slave *sdw; + + struct regulator *vdd_p; + struct regulator *vdd_d; + struct regulator_bulk_data core_supplies[CS42L43_N_SUPPLIES]; + + struct gpio_desc *reset; + + int irq; + struct regmap_irq_chip irq_chip; + struct regmap_irq_chip_data *irq_data; + + struct work_struct boot_work; + struct completion device_attach; + struct completion device_detach; + struct completion firmware_download; + int firmware_error; + + unsigned int sdw_freq; + /* Lock to gate control of the PLL and its sources. */ + struct mutex pll_lock; + + bool sdw_pll_active; + bool attached; + bool hw_lock; +}; + +#endif /* CS42L43_CORE_EXT_H */ -- cgit v1.2.3 From d5282a53929791071b17dde3eed52e40f76b101c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Aug 2023 11:46:00 +0100 Subject: pinctrl: cs42l43: Add support for the cs42l43 The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed for portable applications. It provides a high dynamic range, stereo DAC for headphone output, two integrated Class D amplifiers for loudspeakers, and two ADCs for wired headset microphone input or stereo line input. PDM inputs are provided for digital microphones. Add a basic pinctrl driver which supports driver strength for the various pins, gpios, and pinmux for the 2 multi-function pins. Reviewed-by: Linus Walleij Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-5-ckeepax@opensource.cirrus.com Signed-off-by: Lee Jones --- MAINTAINERS | 1 + drivers/pinctrl/cirrus/Kconfig | 11 + drivers/pinctrl/cirrus/Makefile | 2 + drivers/pinctrl/cirrus/pinctrl-cs42l43.c | 609 +++++++++++++++++++++++++++++++ 4 files changed, 623 insertions(+) create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs42l43.c diff --git a/MAINTAINERS b/MAINTAINERS index 45aa18c45d20..4e35a4880cf8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4880,6 +4880,7 @@ L: patches@opensource.cirrus.com S: Maintained F: Documentation/devicetree/bindings/sound/cirrus,cs* F: drivers/mfd/cs42l43* +F: drivers/pinctrl/cirrus/pinctrl-cs42l43* F: include/dt-bindings/sound/cs* F: include/linux/mfd/cs42l43* F: include/sound/cs* diff --git a/drivers/pinctrl/cirrus/Kconfig b/drivers/pinctrl/cirrus/Kconfig index 530426a74f75..d6318cb57aff 100644 --- a/drivers/pinctrl/cirrus/Kconfig +++ b/drivers/pinctrl/cirrus/Kconfig @@ -1,4 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only +config PINCTRL_CS42L43 + tristate "Cirrus Logic CS42L43 Pinctrl Driver" + depends on MFD_CS42L43 + select GPIOLIB + select PINMUX + select PINCONF + select GENERIC_PINCONF + help + Select this to support the GPIO/Pinctrl functions of the Cirrus + Logic CS42L43 PC CODEC. + config PINCTRL_LOCHNAGAR tristate "Cirrus Logic Lochnagar pinctrl driver" depends on MFD_LOCHNAGAR diff --git a/drivers/pinctrl/cirrus/Makefile b/drivers/pinctrl/cirrus/Makefile index a484518c840e..9b618d766907 100644 --- a/drivers/pinctrl/cirrus/Makefile +++ b/drivers/pinctrl/cirrus/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # Cirrus Logic pinctrl drivers +obj-$(CONFIG_PINCTRL_CS42L43) += pinctrl-cs42l43.o + obj-$(CONFIG_PINCTRL_LOCHNAGAR) += pinctrl-lochnagar.o pinctrl-madera-objs := pinctrl-madera-core.o diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c new file mode 100644 index 000000000000..c09646318419 --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c @@ -0,0 +1,609 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 Pinctrl and GPIO driver +// +// Copyright (c) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../pinctrl-utils.h" + +#define CS42L43_NUM_GPIOS 3 + +struct cs42l43_pin { + struct gpio_chip gpio_chip; + + struct device *dev; + struct regmap *regmap; + bool shutters_locked; +}; + +struct cs42l43_pin_data { + unsigned int reg; + unsigned int shift; + unsigned int mask; +}; + +#define CS42L43_PIN(_number, _name, _reg, _field) { \ + .number = _number, .name = _name, \ + .drv_data = &((struct cs42l43_pin_data){ \ + .reg = CS42L43_##_reg, \ + .shift = CS42L43_##_field##_DRV_SHIFT, \ + .mask = CS42L43_##_field##_DRV_MASK, \ + }), \ +} + +static const struct pinctrl_pin_desc cs42l43_pin_pins[] = { + CS42L43_PIN(0, "gpio1", DRV_CTRL4, GPIO1), + CS42L43_PIN(1, "gpio2", DRV_CTRL4, GPIO2), + CS42L43_PIN(2, "gpio3", DRV_CTRL4, GPIO3), + CS42L43_PIN(3, "asp_dout", DRV_CTRL1, ASP_DOUT), + CS42L43_PIN(4, "asp_fsync", DRV_CTRL1, ASP_FSYNC), + CS42L43_PIN(5, "asp_bclk", DRV_CTRL1, ASP_BCLK), + CS42L43_PIN(6, "pdmout2_clk", DRV_CTRL3, PDMOUT2_CLK), + CS42L43_PIN(7, "pdmout2_data", DRV_CTRL3, PDMOUT2_DATA), + CS42L43_PIN(8, "pdmout1_clk", DRV_CTRL3, PDMOUT1_CLK), + CS42L43_PIN(9, "pdmout1_data", DRV_CTRL3, PDMOUT1_DATA), + CS42L43_PIN(10, "i2c_sda", DRV_CTRL3, I2C_SDA), + CS42L43_PIN(11, "i2c_scl", DRV_CTRL_5, I2C_SCL), + CS42L43_PIN(12, "spi_miso", DRV_CTRL3, SPI_MISO), + CS42L43_PIN(13, "spi_sck", DRV_CTRL_5, SPI_SCK), + CS42L43_PIN(14, "spi_ssb", DRV_CTRL_5, SPI_SSB), +}; + +static const unsigned int cs42l43_pin_gpio1_pins[] = { 0 }; +static const unsigned int cs42l43_pin_gpio2_pins[] = { 1 }; +static const unsigned int cs42l43_pin_gpio3_pins[] = { 2 }; +static const unsigned int cs42l43_pin_asp_pins[] = { 3, 4, 5 }; +static const unsigned int cs42l43_pin_pdmout2_pins[] = { 6, 7 }; +static const unsigned int cs42l43_pin_pdmout1_pins[] = { 8, 9 }; +static const unsigned int cs42l43_pin_i2c_pins[] = { 10, 11 }; +static const unsigned int cs42l43_pin_spi_pins[] = { 12, 13, 14 }; + +#define CS42L43_PINGROUP(_name) \ + PINCTRL_PINGROUP(#_name, cs42l43_pin_##_name##_pins, \ + ARRAY_SIZE(cs42l43_pin_##_name##_pins)) + +static const struct pingroup cs42l43_pin_groups[] = { + CS42L43_PINGROUP(gpio1), + CS42L43_PINGROUP(gpio2), + CS42L43_PINGROUP(gpio3), + CS42L43_PINGROUP(asp), + CS42L43_PINGROUP(pdmout2), + CS42L43_PINGROUP(pdmout1), + CS42L43_PINGROUP(i2c), + CS42L43_PINGROUP(spi), +}; + +static int cs42l43_pin_get_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(cs42l43_pin_groups); +} + +static const char *cs42l43_pin_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group_idx) +{ + return cs42l43_pin_groups[group_idx].name; +} + +static int cs42l43_pin_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group_idx, + const unsigned int **pins, + unsigned int *num_pins) +{ + *pins = cs42l43_pin_groups[group_idx].pins; + *num_pins = cs42l43_pin_groups[group_idx].npins; + + return 0; +} + +static const struct pinctrl_ops cs42l43_pin_group_ops = { + .get_groups_count = cs42l43_pin_get_groups_count, + .get_group_name = cs42l43_pin_get_group_name, + .get_group_pins = cs42l43_pin_get_group_pins, +#if IS_ENABLED(CONFIG_OF) + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinconf_generic_dt_free_map, +#endif +}; + +enum cs42l43_pin_funcs { + CS42L43_FUNC_GPIO, + CS42L43_FUNC_SPDIF, + CS42L43_FUNC_IRQ, + CS42L43_FUNC_MIC_SHT, + CS42L43_FUNC_SPK_SHT, + CS42L43_FUNC_MAX +}; + +static const char * const cs42l43_pin_funcs[] = { + "gpio", "spdif", "irq", "mic-shutter", "spk-shutter", +}; + +static const char * const cs42l43_pin_gpio_groups[] = { "gpio1", "gpio3" }; +static const char * const cs42l43_pin_spdif_groups[] = { "gpio3" }; +static const char * const cs42l43_pin_irq_groups[] = { "gpio1" }; +static const char * const cs42l43_pin_shutter_groups[] = { "gpio1", "gpio2", "gpio3" }; + +static const struct pinfunction cs42l43_pin_func_groups[] = { + PINCTRL_PINFUNCTION("gpio", cs42l43_pin_gpio_groups, + ARRAY_SIZE(cs42l43_pin_gpio_groups)), + PINCTRL_PINFUNCTION("spdif", cs42l43_pin_spdif_groups, + ARRAY_SIZE(cs42l43_pin_spdif_groups)), + PINCTRL_PINFUNCTION("irq", cs42l43_pin_irq_groups, + ARRAY_SIZE(cs42l43_pin_irq_groups)), + PINCTRL_PINFUNCTION("mic-shutter", cs42l43_pin_shutter_groups, + ARRAY_SIZE(cs42l43_pin_shutter_groups)), + PINCTRL_PINFUNCTION("spk-shutter", cs42l43_pin_shutter_groups, + ARRAY_SIZE(cs42l43_pin_shutter_groups)), +}; + +static_assert(ARRAY_SIZE(cs42l43_pin_funcs) == CS42L43_FUNC_MAX); +static_assert(ARRAY_SIZE(cs42l43_pin_func_groups) == CS42L43_FUNC_MAX); + +static int cs42l43_pin_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(cs42l43_pin_funcs); +} + +static const char *cs42l43_pin_get_func_name(struct pinctrl_dev *pctldev, + unsigned int func_idx) +{ + return cs42l43_pin_funcs[func_idx]; +} + +static int cs42l43_pin_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int func_idx, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = cs42l43_pin_func_groups[func_idx].groups; + *num_groups = cs42l43_pin_func_groups[func_idx].ngroups; + + return 0; +} + +static int cs42l43_pin_set_mux(struct pinctrl_dev *pctldev, + unsigned int func_idx, unsigned int group_idx) +{ + struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int reg, mask, val; + + dev_dbg(priv->dev, "Setting %s to %s\n", + cs42l43_pin_groups[group_idx].name, cs42l43_pin_funcs[func_idx]); + + switch (func_idx) { + case CS42L43_FUNC_MIC_SHT: + reg = CS42L43_SHUTTER_CONTROL; + mask = CS42L43_MIC_SHUTTER_CFG_MASK; + val = 0x2 << (group_idx + CS42L43_MIC_SHUTTER_CFG_SHIFT); + break; + case CS42L43_FUNC_SPK_SHT: + reg = CS42L43_SHUTTER_CONTROL; + mask = CS42L43_SPK_SHUTTER_CFG_MASK; + val = 0x2 << (group_idx + CS42L43_SPK_SHUTTER_CFG_SHIFT); + break; + default: + reg = CS42L43_GPIO_FN_SEL; + mask = BIT(group_idx + CS42L43_GPIO1_FN_SEL_SHIFT); + val = (func_idx == CS42L43_FUNC_GPIO) ? + (0x1 << (group_idx + CS42L43_GPIO1_FN_SEL_SHIFT)) : 0; + break; + } + + if (priv->shutters_locked && reg == CS42L43_SHUTTER_CONTROL) { + dev_err(priv->dev, "Shutter configuration not available\n"); + return -EPERM; + } + + return regmap_update_bits(priv->regmap, reg, mask, val); +} + +static int cs42l43_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int shift = offset + CS42L43_GPIO1_DIR_SHIFT; + int ret; + + dev_dbg(priv->dev, "Setting gpio%d to %s\n", + offset + 1, input ? "input" : "output"); + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for direction: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1, + BIT(shift), !!input << shift); + if (ret) + dev_err(priv->dev, "Failed to set gpio%d direction: %d\n", + offset + 1, ret); + + pm_runtime_put(priv->dev); + + return ret; +} + +static int cs42l43_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + return cs42l43_pin_set_mux(pctldev, 0, offset); +} + +static void cs42l43_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + cs42l43_gpio_set_direction(pctldev, range, offset, true); +} + +static const struct pinmux_ops cs42l43_pin_mux_ops = { + .get_functions_count = cs42l43_pin_get_func_count, + .get_function_name = cs42l43_pin_get_func_name, + .get_function_groups = cs42l43_pin_get_func_groups, + + .set_mux = cs42l43_pin_set_mux, + + .gpio_request_enable = cs42l43_gpio_request_enable, + .gpio_disable_free = cs42l43_gpio_disable_free, + .gpio_set_direction = cs42l43_gpio_set_direction, + + .strict = true, +}; + +static const unsigned int cs42l43_pin_drv_str_ma[] = { 1, 2, 4, 8, 9, 10, 12, 16 }; + +static inline int cs42l43_pin_get_drv_str(struct cs42l43_pin *priv, unsigned int pin) +{ + const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data; + unsigned int val; + int ret; + + ret = regmap_read(priv->regmap, pdat->reg, &val); + if (ret) + return ret; + + return cs42l43_pin_drv_str_ma[(val & pdat->mask) >> pdat->shift]; +} + +static inline int cs42l43_pin_set_drv_str(struct cs42l43_pin *priv, unsigned int pin, + unsigned int ma) +{ + const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data; + int i; + + for (i = 0; i < ARRAY_SIZE(cs42l43_pin_drv_str_ma); i++) { + if (ma == cs42l43_pin_drv_str_ma[i]) { + if ((i << pdat->shift) > pdat->mask) + goto err; + + dev_dbg(priv->dev, "Set drive strength for %s to %d mA\n", + cs42l43_pin_pins[pin].name, ma); + + return regmap_update_bits(priv->regmap, pdat->reg, + pdat->mask, i << pdat->shift); + } + } + +err: + dev_err(priv->dev, "Invalid drive strength for %s: %d mA\n", + cs42l43_pin_pins[pin].name, ma); + return -EINVAL; +} + +static inline int cs42l43_pin_get_db(struct cs42l43_pin *priv, unsigned int pin) +{ + unsigned int val; + int ret; + + if (pin >= CS42L43_NUM_GPIOS) + return -ENOTSUPP; + + ret = regmap_read(priv->regmap, CS42L43_GPIO_CTRL2, &val); + if (ret) + return ret; + + if (val & (CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin)) + return 0; + + return 85; // Debounce is roughly 85uS +} + +static inline int cs42l43_pin_set_db(struct cs42l43_pin *priv, unsigned int pin, + unsigned int us) +{ + if (pin >= CS42L43_NUM_GPIOS) + return -ENOTSUPP; + + dev_dbg(priv->dev, "Set debounce %s for %s\n", + str_on_off(us), cs42l43_pin_pins[pin].name); + + return regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL2, + CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin, + !!us << pin); +} + +static int cs42l43_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int param = pinconf_to_config_param(*config); + int ret; + + switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH: + ret = cs42l43_pin_get_drv_str(priv, pin); + if (ret < 0) + return ret; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = cs42l43_pin_get_db(priv, pin); + if (ret < 0) + return ret; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, ret); + + return 0; +} + +static int cs42l43_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int val; + int ret; + + while (num_configs) { + val = pinconf_to_config_argument(*configs); + + switch (pinconf_to_config_param(*configs)) { + case PIN_CONFIG_DRIVE_STRENGTH: + ret = cs42l43_pin_set_drv_str(priv, pin, val); + if (ret) + return ret; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = cs42l43_pin_set_db(priv, pin, val); + if (ret) + return ret; + break; + default: + return -ENOTSUPP; + } + + configs++; + num_configs--; + } + + return 0; +} + +static int cs42l43_pin_config_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned long *config) +{ + int i, ret; + + for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) { + ret = cs42l43_pin_config_get(pctldev, + cs42l43_pin_groups[selector].pins[i], + config); + if (ret) + return ret; + } + + return 0; +} + +static int cs42l43_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + int i, ret; + + for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) { + ret = cs42l43_pin_config_set(pctldev, + cs42l43_pin_groups[selector].pins[i], + configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops cs42l43_pin_conf_ops = { + .is_generic = true, + + .pin_config_get = cs42l43_pin_config_get, + .pin_config_set = cs42l43_pin_config_set, + .pin_config_group_get = cs42l43_pin_config_group_get, + .pin_config_group_set = cs42l43_pin_config_group_set, +}; + +static struct pinctrl_desc cs42l43_pin_desc = { + .name = "cs42l43-pinctrl", + .owner = THIS_MODULE, + + .pins = cs42l43_pin_pins, + .npins = ARRAY_SIZE(cs42l43_pin_pins), + + .pctlops = &cs42l43_pin_group_ops, + .pmxops = &cs42l43_pin_mux_ops, + .confops = &cs42l43_pin_conf_ops, +}; + +static int cs42l43_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct cs42l43_pin *priv = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for get: %d\n", ret); + return ret; + } + + ret = regmap_read(priv->regmap, CS42L43_GPIO_STS, &val); + if (ret) + dev_err(priv->dev, "Failed to get gpio%d: %d\n", offset + 1, ret); + else + ret = !!(val & BIT(offset + CS42L43_GPIO1_STS_SHIFT)); + + pm_runtime_put(priv->dev); + + return ret; +} + +static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct cs42l43_pin *priv = gpiochip_get_data(chip); + unsigned int shift = offset + CS42L43_GPIO1_LVL_SHIFT; + int ret; + + dev_dbg(priv->dev, "Setting gpio%d to %s\n", + offset + 1, value ? "high" : "low"); + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for set: %d\n", ret); + return; + } + + ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1, + BIT(shift), value << shift); + if (ret) + dev_err(priv->dev, "Failed to set gpio%d: %d\n", offset + 1, ret); + + pm_runtime_put(priv->dev); +} + +static int cs42l43_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int cs42l43_gpio_direction_out(struct gpio_chip *chip, + unsigned int offset, int value) +{ + cs42l43_gpio_set(chip, offset, value); + + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static int cs42l43_gpio_add_pin_ranges(struct gpio_chip *chip) +{ + struct cs42l43_pin *priv = gpiochip_get_data(chip); + int ret; + + ret = gpiochip_add_pin_range(&priv->gpio_chip, priv->gpio_chip.label, + 0, 0, CS42L43_NUM_GPIOS); + if (ret) + dev_err(priv->dev, "Failed to add GPIO pin range: %d\n", ret); + + return ret; +} + +static int cs42l43_pin_probe(struct platform_device *pdev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); + struct cs42l43_pin *priv; + struct pinctrl_dev *pctldev; + struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->regmap = cs42l43->regmap; + + priv->shutters_locked = cs42l43->hw_lock; + + priv->gpio_chip.request = gpiochip_generic_request; + priv->gpio_chip.free = gpiochip_generic_free; + priv->gpio_chip.direction_input = cs42l43_gpio_direction_in; + priv->gpio_chip.direction_output = cs42l43_gpio_direction_out; + priv->gpio_chip.add_pin_ranges = cs42l43_gpio_add_pin_ranges; + priv->gpio_chip.get = cs42l43_gpio_get; + priv->gpio_chip.set = cs42l43_gpio_set; + priv->gpio_chip.label = dev_name(priv->dev); + priv->gpio_chip.parent = priv->dev; + priv->gpio_chip.can_sleep = true; + priv->gpio_chip.base = -1; + priv->gpio_chip.ngpio = CS42L43_NUM_GPIOS; + + if (is_of_node(fwnode)) { + fwnode = fwnode_get_named_child_node(fwnode, "pinctrl"); + + if (fwnode && !fwnode->dev) + fwnode->dev = priv->dev; + } + + priv->gpio_chip.fwnode = fwnode; + + device_set_node(priv->dev, fwnode); + + devm_pm_runtime_enable(priv->dev); + pm_runtime_idle(priv->dev); + + pctldev = devm_pinctrl_register(priv->dev, &cs42l43_pin_desc, priv); + if (IS_ERR(pctldev)) + return dev_err_probe(priv->dev, PTR_ERR(pctldev), + "Failed to register pinctrl\n"); + + ret = devm_gpiochip_add_data(priv->dev, &priv->gpio_chip, priv); + if (ret) + return dev_err_probe(priv->dev, ret, + "Failed to register gpiochip\n"); + + return 0; +} + +static const struct platform_device_id cs42l43_pin_id_table[] = { + { "cs42l43-pinctrl", }, + {} +}; +MODULE_DEVICE_TABLE(platform, cs42l43_pin_id_table); + +static struct platform_driver cs42l43_pin_driver = { + .driver = { + .name = "cs42l43-pinctrl", + }, + .probe = cs42l43_pin_probe, + .id_table = cs42l43_pin_id_table, +}; +module_platform_driver(cs42l43_pin_driver); + +MODULE_DESCRIPTION("CS42L43 Pinctrl Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From c4c3c32d088d5a432d3c40efef80d1b64743b6bc Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:33 +0800 Subject: ASoC: mediatek: mt7986: add common header Add header files for register definition and structure. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-2-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt7986/mt7986-afe-common.h | 49 +++++++ sound/soc/mediatek/mt7986/mt7986-reg.h | 196 ++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-common.h create mode 100644 sound/soc/mediatek/mt7986/mt7986-reg.h diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h new file mode 100644 index 000000000000..fc3bb31e5167 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#ifndef _MT_7986_AFE_COMMON_H_ +#define _MT_7986_AFE_COMMON_H_ + +#include +#include +#include +#include +#include "../common/mtk-base-afe.h" + +enum { + MT7986_MEMIF_DL1, + MT7986_MEMIF_VUL12, + MT7986_MEMIF_NUM, + MT7986_DAI_ETDM = MT7986_MEMIF_NUM, + MT7986_DAI_NUM, +}; + +enum { + MT7986_IRQ_0, + MT7986_IRQ_1, + MT7986_IRQ_2, + MT7986_IRQ_NUM, +}; + +struct mt7986_afe_private { + struct clk_bulk_data *clks; + int num_clks; + + int pm_runtime_bypass_reg_ctl; + + /* dai */ + void *dai_priv[MT7986_DAI_NUM]; +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, + unsigned int rate); + +/* dai register */ +int mt7986_dai_etdm_register(struct mtk_base_afe *afe); +#endif diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h new file mode 100644 index 000000000000..c2b200743c3f --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-reg.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-reg.h -- MediaTek 7986 audio driver reg definition + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#ifndef _MT7986_REG_H_ +#define _MT7986_REG_H_ + +#define AUDIO_TOP_CON2 0x0008 +#define AUDIO_TOP_CON4 0x0010 +#define AUDIO_ENGEN_CON0 0x0014 +#define AFE_IRQ_MCU_EN 0x0100 +#define AFE_IRQ_MCU_STATUS 0x0120 +#define AFE_IRQ_MCU_CLR 0x0128 +#define AFE_IRQ0_MCU_CFG0 0x0140 +#define AFE_IRQ0_MCU_CFG1 0x0144 +#define AFE_IRQ1_MCU_CFG0 0x0148 +#define AFE_IRQ1_MCU_CFG1 0x014c +#define AFE_IRQ2_MCU_CFG0 0x0150 +#define AFE_IRQ2_MCU_CFG1 0x0154 +#define ETDM_IN5_CON0 0x13f0 +#define ETDM_IN5_CON1 0x13f4 +#define ETDM_IN5_CON2 0x13f8 +#define ETDM_IN5_CON3 0x13fc +#define ETDM_IN5_CON4 0x1400 +#define ETDM_OUT5_CON0 0x1570 +#define ETDM_OUT5_CON4 0x1580 +#define ETDM_OUT5_CON5 0x1584 +#define ETDM_4_7_COWORK_CON0 0x15e0 +#define ETDM_4_7_COWORK_CON1 0x15e4 +#define AFE_CONN018_1 0x1b44 +#define AFE_CONN018_4 0x1b50 +#define AFE_CONN019_1 0x1b64 +#define AFE_CONN019_4 0x1b70 +#define AFE_CONN124_1 0x2884 +#define AFE_CONN124_4 0x2890 +#define AFE_CONN125_1 0x28a4 +#define AFE_CONN125_4 0x28b0 +#define AFE_CONN_RS_0 0x3920 +#define AFE_CONN_RS_3 0x392c +#define AFE_CONN_16BIT_0 0x3960 +#define AFE_CONN_16BIT_3 0x396c +#define AFE_CONN_24BIT_0 0x3980 +#define AFE_CONN_24BIT_3 0x398c +#define AFE_MEMIF_CON0 0x3d98 +#define AFE_MEMIF_RD_MON 0x3da0 +#define AFE_MEMIF_WR_MON 0x3da4 +#define AFE_DL0_BASE_MSB 0x3e40 +#define AFE_DL0_BASE 0x3e44 +#define AFE_DL0_CUR_MSB 0x3e48 +#define AFE_DL0_CUR 0x3e4c +#define AFE_DL0_END_MSB 0x3e50 +#define AFE_DL0_END 0x3e54 +#define AFE_DL0_RCH_MON 0x3e58 +#define AFE_DL0_LCH_MON 0x3e5c +#define AFE_DL0_CON0 0x3e60 +#define AFE_VUL0_BASE_MSB 0x4220 +#define AFE_VUL0_BASE 0x4224 +#define AFE_VUL0_CUR_MSB 0x4228 +#define AFE_VUL0_CUR 0x422c +#define AFE_VUL0_END_MSB 0x4230 +#define AFE_VUL0_END 0x4234 +#define AFE_VUL0_CON0 0x4238 + +#define AFE_MAX_REGISTER AFE_VUL0_CON0 +#define AFE_IRQ_STATUS_BITS 0x7 +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0xffffff + +/* AUDIO_TOP_CON2 */ +#define CLK_OUT5_PDN BIT(14) +#define CLK_OUT5_PDN_MASK BIT(14) +#define CLK_IN5_PDN BIT(7) +#define CLK_IN5_PDN_MASK BIT(7) + +/* AUDIO_TOP_CON4 */ +#define PDN_APLL_TUNER2 BIT(12) +#define PDN_APLL_TUNER2_MASK BIT(12) + +/* AUDIO_ENGEN_CON0 */ +#define AUD_APLL2_EN BIT(3) +#define AUD_APLL2_EN_MASK BIT(3) +#define AUD_26M_EN BIT(0) +#define AUD_26M_EN_MASK BIT(0) + +/* AFE_DL0_CON0 */ +#define DL0_ON_SFT 28 +#define DL0_ON_MASK 0x1 +#define DL0_ON_MASK_SFT BIT(28) +#define DL0_MINLEN_SFT 20 +#define DL0_MINLEN_MASK 0xf +#define DL0_MINLEN_MASK_SFT (0xf << 20) +#define DL0_MODE_SFT 8 +#define DL0_MODE_MASK 0x1f +#define DL0_MODE_MASK_SFT (0x1f << 8) +#define DL0_PBUF_SIZE_SFT 5 +#define DL0_PBUF_SIZE_MASK 0x3 +#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL0_MONO_SFT 4 +#define DL0_MONO_MASK 0x1 +#define DL0_MONO_MASK_SFT BIT(4) +#define DL0_HALIGN_SFT 2 +#define DL0_HALIGN_MASK 0x1 +#define DL0_HALIGN_MASK_SFT BIT(2) +#define DL0_HD_MODE_SFT 0 +#define DL0_HD_MODE_MASK 0x3 +#define DL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL0_CON0 */ +#define VUL0_ON_SFT 28 +#define VUL0_ON_MASK 0x1 +#define VUL0_ON_MASK_SFT BIT(28) +#define VUL0_MODE_SFT 8 +#define VUL0_MODE_MASK 0x1f +#define VUL0_MODE_MASK_SFT (0x1f << 8) +#define VUL0_MONO_SFT 4 +#define VUL0_MONO_MASK 0x1 +#define VUL0_MONO_MASK_SFT BIT(4) +#define VUL0_HALIGN_SFT 2 +#define VUL0_HALIGN_MASK 0x1 +#define VUL0_HALIGN_MASK_SFT BIT(2) +#define VUL0_HD_MODE_SFT 0 +#define VUL0_HD_MODE_MASK 0x3 +#define VUL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_IRQ_MCU_CON */ +#define IRQ_MCU_MODE_SFT 4 +#define IRQ_MCU_MODE_MASK 0x1f +#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4) +#define IRQ_MCU_ON_SFT 0 +#define IRQ_MCU_ON_MASK 0x1 +#define IRQ_MCU_ON_MASK_SFT BIT(0) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT BIT(0) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT BIT(1) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT BIT(2) + +/* ETDM_IN5_CON2 */ +#define IN_CLK_SRC(x) ((x) << 10) +#define IN_CLK_SRC_SFT 10 +#define IN_CLK_SRC_MASK GENMASK(12, 10) + +/* ETDM_IN5_CON3 */ +#define IN_SEL_FS(x) ((x) << 26) +#define IN_SEL_FS_SFT 26 +#define IN_SEL_FS_MASK GENMASK(30, 26) + +/* ETDM_IN5_CON4 */ +#define IN_RELATCH(x) ((x) << 20) +#define IN_RELATCH_SFT 20 +#define IN_RELATCH_MASK GENMASK(24, 20) +#define IN_CLK_INV BIT(18) +#define IN_CLK_INV_MASK BIT(18) + +/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */ +#define RELATCH_SRC_MASK GENMASK(30, 28) +#define ETDM_CH_NUM_MASK GENMASK(27, 23) +#define ETDM_WRD_LEN_MASK GENMASK(20, 16) +#define ETDM_BIT_LEN_MASK GENMASK(15, 11) +#define ETDM_FMT_MASK GENMASK(8, 6) +#define ETDM_SYNC BIT(1) +#define ETDM_SYNC_MASK BIT(1) +#define ETDM_EN BIT(0) +#define ETDM_EN_MASK BIT(0) + +/* ETDM_OUT5_CON4 */ +#define OUT_RELATCH(x) ((x) << 24) +#define OUT_RELATCH_SFT 24 +#define OUT_RELATCH_MASK GENMASK(28, 24) +#define OUT_CLK_SRC(x) ((x) << 6) +#define OUT_CLK_SRC_SFT 6 +#define OUT_CLK_SRC_MASK GENMASK(8, 6) +#define OUT_SEL_FS(x) (x) +#define OUT_SEL_FS_SFT 0 +#define OUT_SEL_FS_MASK GENMASK(4, 0) + +/* ETDM_OUT5_CON5 */ +#define ETDM_CLK_DIV BIT(12) +#define ETDM_CLK_DIV_MASK BIT(12) +#define OUT_CLK_INV BIT(9) +#define OUT_CLK_INV_MASK BIT(9) + +/* ETDM_4_7_COWORK_CON0 */ +#define OUT_SEL(x) ((x) << 12) +#define OUT_SEL_SFT 12 +#define OUT_SEL_MASK GENMASK(15, 12) +#endif -- cgit v1.2.3 From 9f8df795ae8daa0051fe15b27c7a3b3842d3d91f Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:34 +0800 Subject: ASoC: mediatek: mt7986: support etdm in platform driver Add mt7986 etdm dai driver support. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-3-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt7986/mt7986-dai-etdm.c | 411 ++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-dai-etdm.c diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c new file mode 100644 index 000000000000..e523d33846fe --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI eTDM Control + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include +#include +#include +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" + +#define HOPPING_CLK 0 +#define APLL_CLK 1 +#define MTK_DAI_ETDM_FORMAT_I2S 0 +#define MTK_DAI_ETDM_FORMAT_DSPA 4 +#define MTK_DAI_ETDM_FORMAT_DSPB 5 + +enum { + MTK_ETDM_RATE_8K = 0, + MTK_ETDM_RATE_12K = 1, + MTK_ETDM_RATE_16K = 2, + MTK_ETDM_RATE_24K = 3, + MTK_ETDM_RATE_32K = 4, + MTK_ETDM_RATE_48K = 5, + MTK_ETDM_RATE_96K = 7, + MTK_ETDM_RATE_192K = 9, + MTK_ETDM_RATE_11K = 16, + MTK_ETDM_RATE_22K = 17, + MTK_ETDM_RATE_44K = 18, + MTK_ETDM_RATE_88K = 19, + MTK_ETDM_RATE_176K = 20, +}; + +struct mtk_dai_etdm_priv { + bool bck_inv; + bool lrck_inv; + bool slave_mode; + unsigned int format; +}; + +static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_ETDM_RATE_8K; + case 11025: + return MTK_ETDM_RATE_11K; + case 12000: + return MTK_ETDM_RATE_12K; + case 16000: + return MTK_ETDM_RATE_16K; + case 22050: + return MTK_ETDM_RATE_22K; + case 24000: + return MTK_ETDM_RATE_24K; + case 32000: + return MTK_ETDM_RATE_32K; + case 44100: + return MTK_ETDM_RATE_44K; + case 48000: + return MTK_ETDM_RATE_48K; + case 88200: + return MTK_ETDM_RATE_88K; + case 96000: + return MTK_ETDM_RATE_96K; + case 176400: + return MTK_ETDM_RATE_176K; + case 192000: + return MTK_ETDM_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_ETDM_RATE_48K); + return MTK_ETDM_RATE_48K; + } +} + +static int get_etdm_wlen(unsigned int bitwidth) +{ + return bitwidth <= 16 ? 16 : 32; +} + +/* dai component */ +/* interconnection */ + +static const struct snd_kcontrol_new o124_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new o125_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { + + /* DL */ + SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0), + /* UL */ + SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)), + SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)), +}; + +static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { + {"I150", NULL, "ETDM Capture"}, + {"I151", NULL, "ETDM Capture"}, + {"ETDM Playback", NULL, "O124"}, + {"ETDM Playback", NULL, "O125"}, + {"O124", "I032_Switch", "I032"}, + {"O125", "I033_Switch", "I033"}, +}; + +/* dai ops */ +static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0); + + return 0; +} + +static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, + CLK_OUT5_PDN); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, + CLK_IN5_PDN); + + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); +} + +static unsigned int get_etdm_ch_fixup(unsigned int channels) +{ + if (channels > 16) + return 24; + else if (channels > 8) + return 16; + else if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static int mtk_dai_etdm_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai, + int stream) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + unsigned int rate = params_rate(params); + unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate); + unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate); + unsigned int channels = params_channels(params); + unsigned int bit_width = params_width(params); + unsigned int wlen = get_etdm_wlen(bit_width); + unsigned int val = 0; + unsigned int mask = 0; + + dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n", + __func__, stream, rate, bit_width); + + /* CON0 */ + mask |= ETDM_BIT_LEN_MASK; + val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1); + mask |= ETDM_WRD_LEN_MASK; + val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1); + mask |= ETDM_FMT_MASK; + val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format); + mask |= ETDM_CH_NUM_MASK; + val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1); + mask |= RELATCH_SRC_MASK; + val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK); + + switch (stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + /* set ETDM_OUT5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val); + + /* set ETDM_OUT5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_RELATCH_MASK, OUT_RELATCH(afe_rate)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate)); + + /* set ETDM_OUT5_CON5 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, + ETDM_CLK_DIV_MASK, ETDM_CLK_DIV); + break; + case SNDRV_PCM_STREAM_CAPTURE: + /* set ETDM_IN5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val); + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, + ETDM_SYNC_MASK, ETDM_SYNC); + + /* set ETDM_IN5_CON2 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON2, + IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK)); + + /* set ETDM_IN5_CON3 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON3, + IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate)); + + /* set ETDM_IN5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON4, + IN_RELATCH_MASK, IN_RELATCH(afe_rate)); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK); + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE); + + return 0; +} + +static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + ETDM_EN); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + ETDM_EN); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + 0); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data; + void *priv_data; + + switch (dai->id) { + case MT7986_DAI_ETDM: + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv), + GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + afe_priv->dai_priv[dai->id] = priv_data; + etdm_data = afe_priv->dai_priv[dai->id]; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA; + break; + case SND_SOC_DAIFMT_DSP_B: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_NB_IF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = true; + break; + case SND_SOC_DAIFMT_IB_NF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_IB_IF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + etdm_data->slave_mode = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + etdm_data->slave_mode = false; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +/* dai driver */ +#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { + { + .name = "ETDM", + .id = MT7986_DAI_ETDM, + .capture = { + .stream_name = "ETDM Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .playback = { + .stream_name = "ETDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .ops = &mtk_dai_etdm_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + }, +}; + +int mt7986_dai_etdm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_etdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver); + + dai->dapm_widgets = mtk_dai_etdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets); + dai->dapm_routes = mtk_dai_etdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes); + + return 0; +} -- cgit v1.2.3 From 8d0d4884ba2cdabc823dc263c987bb22aae5fa5e Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:35 +0800 Subject: ASoC: mediatek: mt7986: add platform driver Add mt7986 platform driver. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-4-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt7986/Makefile | 8 + sound/soc/mediatek/mt7986/mt7986-afe-pcm.c | 622 +++++++++++++++++++++++++++++ 4 files changed, 641 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/Makefile create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-pcm.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 90db67e0ce4f..558827755a8d 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -54,6 +54,16 @@ config SND_SOC_MT6797_MT6351 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT7986 + tristate "ASoC support for Mediatek MT7986 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for MediaTek MT7986 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3de38cfc69e5..3938e7f75c2e 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ +obj-$(CONFIG_SND_SOC_MT7986) += mt7986/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile new file mode 100644 index 000000000000..de0742a67cae --- /dev/null +++ b/sound/soc/mediatek/mt7986/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt7986-afe-objs := \ + mt7986-afe-pcm.o \ + mt7986-dai-etdm.o + +obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c new file mode 100644 index 000000000000..d497e1129889 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC AFE platform driver for MT7986 + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include +#include +#include +#include +#include + +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 13, + MTK_AFE_RATE_96K = 14, + MTK_AFE_RATE_176K = 17, + MTK_AFE_RATE_192K = 18, +}; + +enum { + CLK_INFRA_AUD_BUS_CK = 0, + CLK_INFRA_AUD_26M_CK, + CLK_INFRA_AUD_L_CK, + CLK_INFRA_AUD_AUD_CK, + CLK_INFRA_AUD_EG2_CK, + CLK_NUM +}; + +static const char *aud_clks[CLK_NUM] = { + [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck", + [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck", + [CLK_INFRA_AUD_L_CK] = "aud_l_ck", + [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck", + [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck", +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static const struct snd_pcm_hardware mt7986_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt7986_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +static int mt7986_irq_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT7986_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +static const struct snd_kcontrol_new o018_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0), +}; + +static const struct snd_kcontrol_new o019_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = { + /* DL */ + SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* UL */ + SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0, + o018_mix, ARRAY_SIZE(o018_mix)), + SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0, + o019_mix, ARRAY_SIZE(o019_mix)), +}; + +static const struct snd_soc_dapm_route mt7986_memif_routes[] = { + {"I032", NULL, "DL1"}, + {"I033", NULL, "DL1"}, + {"UL1", NULL, "O018"}, + {"UL1", NULL, "O019"}, + {"O018", "I150_Switch", "I150"}, + {"O019", "I151_Switch", "I151"}, +}; + +static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = { + .name = "mt7986-afe-pcm-dai", +}; + +static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = { + [MT7986_MEMIF_DL1] = { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .reg_ofs_base = AFE_DL0_BASE, + .reg_ofs_cur = AFE_DL0_CUR, + .reg_ofs_end = AFE_DL0_END, + .reg_ofs_base_msb = AFE_DL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL0_CUR_MSB, + .reg_ofs_end_msb = AFE_DL0_END_MSB, + .fs_reg = AFE_DL0_CON0, + .fs_shift = DL0_MODE_SFT, + .fs_maskbit = DL0_MODE_MASK, + .mono_reg = AFE_DL0_CON0, + .mono_shift = DL0_MONO_SFT, + .enable_reg = AFE_DL0_CON0, + .enable_shift = DL0_ON_SFT, + .hd_reg = AFE_DL0_CON0, + .hd_shift = DL0_HD_MODE_SFT, + .hd_align_reg = AFE_DL0_CON0, + .hd_align_mshift = DL0_HALIGN_SFT, + .pbuf_reg = AFE_DL0_CON0, + .pbuf_shift = DL0_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL0_CON0, + .minlen_shift = DL0_MINLEN_SFT, + }, + [MT7986_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT7986_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL0_BASE, + .reg_ofs_cur = AFE_VUL0_CUR, + .reg_ofs_end = AFE_VUL0_END, + .reg_ofs_base_msb = AFE_VUL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL0_END_MSB, + .fs_reg = AFE_VUL0_CON0, + .fs_shift = VUL0_MODE_SFT, + .fs_maskbit = VUL0_MODE_MASK, + .mono_reg = AFE_VUL0_CON0, + .mono_shift = VUL0_MONO_SFT, + .enable_reg = AFE_VUL0_CON0, + .enable_shift = VUL0_ON_SFT, + .hd_reg = AFE_VUL0_CON0, + .hd_shift = VUL0_HD_MODE_SFT, + .hd_align_reg = AFE_VUL0_CON0, + .hd_align_mshift = VUL0_HALIGN_SFT, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = { + [MT7986_IRQ_0] = { + .id = MT7986_IRQ_0, + .irq_cnt_reg = AFE_IRQ0_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ0_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ0_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT7986_IRQ_1] = { + .id = MT7986_IRQ_1, + .irq_cnt_reg = AFE_IRQ1_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ1_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ1_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT7986_IRQ_2] = { + .id = MT7986_IRQ_2, + .irq_cnt_reg = AFE_IRQ2_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ2_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ2_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, +}; + +static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Those auto-gen regs are read-only, so put it as volatile because + * volatile registers cannot be cached, which means that they cannot + * be set when power is off + */ + + switch (reg) { + case AFE_DL0_CUR_MSB: + case AFE_DL0_CUR: + case AFE_DL0_RCH_MON: + case AFE_DL0_LCH_MON: + case AFE_VUL0_CUR_MSB: + case AFE_VUL0_CUR: + case AFE_IRQ_MCU_STATUS: + case AFE_MEMIF_RD_MON: + case AFE_MEMIF_WR_MON: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt7986_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .volatile_reg = mt7986_is_volatile_reg, + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1), +}; + +static int mt7986_init_clock(struct mtk_base_afe *afe) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret, i; + + afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM, + sizeof(*afe_priv->clks), GFP_KERNEL); + if (!afe_priv->clks) + return -ENOMEM; + afe_priv->num_clks = CLK_NUM; + + for (i = 0; i < afe_priv->num_clks; i++) + afe_priv->clks[i].id = aud_clks[i]; + + ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to get clocks\n"); + + return 0; +} + +static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + u32 mcu_en, status, status_mcu; + int i, ret; + irqreturn_t irq_ret = IRQ_HANDLED; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + irq_ret = IRQ_NONE; + goto err_irq; + } + + for (i = 0; i < MT7986_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu); + + return irq_ret; +} + +static int mt7986_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0); + + /* make sure all irq status are cleared, twice intended */ + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + +skip_regmap: + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); + + return 0; +} + +static int mt7986_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + return 0; + + /* enable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, + AUD_APLL2_EN); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, + AUD_26M_EN); + + return 0; +} + +static int mt7986_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt7986_afe_component = { + .name = AFE_PCM_NAME, + .probe = mt7986_afe_component_probe, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, +}; + +static int mt7986_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt7986_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver); + + dai->dapm_widgets = mt7986_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets); + dai->dapm_routes = mt7986_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes); + + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt7986_dai_etdm_register, + mt7986_dai_memif_register, +}; + +static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt7986_afe_private *afe_priv; + struct device *dev; + int i, irq_id, ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + dev = afe->dev; + + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(afe->base_addr)) + return PTR_ERR(afe->base_addr); + + /* initial audio related clock */ + ret = mt7986_init_clock(afe); + if (ret) + return dev_err_probe(dev, ret, "Cannot initialize clocks\n"); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, + &mt7986_afe_regmap_config); + + pm_runtime_put_sync(&pdev->dev); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + afe_priv->pm_runtime_bypass_reg_ctl = false; + + /* init memif */ + afe->memif_size = MT7986_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = -1; + } + + mutex_init(&afe->irq_alloc_lock); + + /* irq initialize */ + afe->irqs_size = MT7986_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id < 0) { + ret = irq_id; + return dev_err_probe(dev, ret, "No irq found\n"); + } + ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) + return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n"); + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) + return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i); + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) + return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); + + afe->mtk_afe_hardware = &mt7986_afe_hardware; + afe->memif_fs = mt7986_memif_fs; + afe->irq_fs = mt7986_irq_fs; + + afe->runtime_resume = mt7986_afe_runtime_resume; + afe->runtime_suspend = mt7986_afe_runtime_suspend; + + /* register component */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt7986_afe_component, + NULL, 0); + if (ret) + return dev_err_probe(dev, ret, "Cannot register AFE component\n"); + + ret = devm_snd_soc_register_component(afe->dev, + &mt7986_afe_pcm_dai_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) + return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n"); + + return 0; +} + +static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt7986_afe_runtime_suspend(&pdev->dev); +} + +static const struct of_device_id mt7986_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt7986-afe" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match); + +static const struct dev_pm_ops mt7986_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend, + mt7986_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt7986_afe_pcm_driver = { + .driver = { + .name = "mt7986-audio", + .of_match_table = mt7986_afe_pcm_dt_match, + .pm = &mt7986_afe_pm_ops, + }, + .probe = mt7986_afe_pcm_dev_probe, + .remove_new = mt7986_afe_pcm_dev_remove, +}; +module_platform_driver(mt7986_afe_pcm_driver); + +MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986"); +MODULE_AUTHOR("Vic Wu "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 9873277fc2ea6e517602c29cb336bb1e43ff528c Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:36 +0800 Subject: ASoC: mediatek: mt7986: add machine driver with wm8960 Add support for mt7986 board with wm8960. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-5-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 ++ sound/soc/mediatek/mt7986/Makefile | 1 + sound/soc/mediatek/mt7986/mt7986-wm8960.c | 196 ++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-wm8960.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 558827755a8d..8d1bc8814486 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -64,6 +64,16 @@ config SND_SOC_MT7986 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT7986_WM8960 + tristate "ASoc Audio driver for MT7986 with WM8960 codec" + depends on SND_SOC_MT7986 && I2C + select SND_SOC_WM8960 + help + This adds support for ASoC machine driver for MediaTek MT7986 + boards with the WM8960 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile index de0742a67cae..fc4c82559b29 100644 --- a/sound/soc/mediatek/mt7986/Makefile +++ b/sound/soc/mediatek/mt7986/Makefile @@ -6,3 +6,4 @@ snd-soc-mt7986-afe-objs := \ mt7986-dai-etdm.o obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o +obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c new file mode 100644 index 000000000000..364d13b1c426 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include + +#include "mt7986-afe-common.h" + +struct mt7986_wm8960_priv { + struct device_node *platform_node; + struct device_node *codec_node; +}; + +static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), +}; + +static const struct snd_kcontrol_new mt7986_wm8960_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("AMIC"), +}; + +SND_SOC_DAILINK_DEFS(playback, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(codec, + DAILINK_COMP_ARRAY(COMP_CPU("ETDM")), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { + /* FE */ + { + .name = "wm8960-playback", + .stream_name = "wm8960-playback", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback), + }, + { + .name = "wm8960-capture", + .stream_name = "wm8960-capture", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture), + }, + /* BE */ + { + .name = "wm8960-codec", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_GATED, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(codec), + }, +}; + +static struct snd_soc_card mt7986_wm8960_card = { + .name = "mt7986-wm8960", + .owner = THIS_MODULE, + .dai_link = mt7986_wm8960_dai_links, + .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links), + .controls = mt7986_wm8960_controls, + .num_controls = ARRAY_SIZE(mt7986_wm8960_controls), + .dapm_widgets = mt7986_wm8960_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets), +}; + +static int mt7986_wm8960_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt7986_wm8960_card; + struct snd_soc_dai_link *dai_link; + struct device_node *platform, *codec; + struct mt7986_wm8960_priv *priv; + int ret, i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform = of_get_child_by_name(pdev->dev.of_node, "platform"); + + if (platform) { + priv->platform_node = of_parse_phandle(platform, "sound-dai", 0); + of_node_put(platform); + + if (!priv->platform_node) { + dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n"); + return -EINVAL; + } + } else { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platforms->name) + continue; + dai_link->platforms->of_node = priv->platform_node; + } + + card->dev = &pdev->dev; + + codec = of_get_child_by_name(pdev->dev.of_node, "codec"); + + if (codec) { + priv->codec_node = of_parse_phandle(codec, "sound-dai", 0); + of_node_put(codec); + + if (!priv->codec_node) { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n"); + return -EINVAL; + } + } else { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Property 'codec' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codecs->name) + continue; + dai_link->codecs->of_node = priv->codec_node; + } + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret); + goto err_of_node_put; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret); + goto err_of_node_put; + } + +err_of_node_put: + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); + return ret; +} + +static void mt7986_wm8960_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card); + + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); +} + +static const struct of_device_id mt7986_wm8960_machine_dt_match[] = { + {.compatible = "mediatek,mt7986-wm8960-sound"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match); + +static struct platform_driver mt7986_wm8960_machine = { + .driver = { + .name = "mt7986-wm8960", + .of_match_table = mt7986_wm8960_machine_dt_match, + }, + .probe = mt7986_wm8960_machine_probe, + .remove_new = mt7986_wm8960_machine_remove, +}; + +module_platform_driver(mt7986_wm8960_machine); + +/* Module information */ +MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver"); +MODULE_AUTHOR("Vic Wu "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mt7986 wm8960 soc card"); -- cgit v1.2.3 From af835f0b49777476528be5a913e5c00fc3789f41 Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:37 +0800 Subject: ASoC: dt-bindings: mediatek,mt7986-wm8960: add mt7986-wm8960 document Add document for mt7986 board with wm8960. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-6-maso.huang@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mediatek,mt7986-wm8960.yaml | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml new file mode 100644 index 000000000000..09247ceea3f7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt7986-wm8960.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7986 sound card with WM8960 codec + +maintainers: + - Maso Huang + +allOf: + - $ref: sound-card-common.yaml# + +properties: + compatible: + const: mediatek,mt7986-wm8960-sound + + platform: + type: object + additionalProperties: false + properties: + sound-dai: + description: The phandle of MT7986 platform. + maxItems: 1 + required: + - sound-dai + + codec: + type: object + additionalProperties: false + properties: + sound-dai: + description: The phandle of wm8960 codec. + maxItems: 1 + required: + - sound-dai + +unevaluatedProperties: false + +required: + - compatible + - audio-routing + - platform + - codec + +examples: + - | + sound { + compatible = "mediatek,mt7986-wm8960-sound"; + model = "mt7986-wm8960"; + audio-routing = + "Headphone", "HP_L", + "Headphone", "HP_R", + "LINPUT1", "AMIC", + "RINPUT1", "AMIC"; + + platform { + sound-dai = <&afe>; + }; + + codec { + sound-dai = <&wm8960>; + }; + }; + +... -- cgit v1.2.3 From b41efc224a5c859ce982ab73e8a05ecac73d4752 Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:38 +0800 Subject: ASoC: dt-bindings: mediatek,mt7986-afe: add audio afe document Add mt7986 audio afe document. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-7-maso.huang@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mediatek,mt7986-afe.yaml | 160 +++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml new file mode 100644 index 000000000000..398efdfe00f5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt7986-afe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek AFE PCM controller for MT7986 + +maintainers: + - Maso Huang + +properties: + compatible: + oneOf: + - const: mediatek,mt7986-afe + - items: + - enum: + - mediatek,mt7981-afe + - mediatek,mt7988-afe + - const: mediatek,mt7986-afe + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 5 + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + - description: audio i2s/pcm mck + + clock-names: + minItems: 5 + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + - const: i2s_m + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt7986-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + + - if: + properties: + compatible: + contains: + const: mediatek,mt7981-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + + - if: + properties: + compatible: + contains: + const: mediatek,mt7988-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + - description: audio i2s/pcm mck + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + - const: i2s_m + +additionalProperties: false + +examples: + - | + #include + #include + #include + + afe@11210000 { + compatible = "mediatek,mt7986-afe"; + reg = <0x11210000 0x9000>; + interrupts = ; + clocks = <&infracfg_ao CLK_INFRA_AUD_BUS_CK>, + <&infracfg_ao CLK_INFRA_AUD_26M_CK>, + <&infracfg_ao CLK_INFRA_AUD_L_CK>, + <&infracfg_ao CLK_INFRA_AUD_AUD_CK>, + <&infracfg_ao CLK_INFRA_AUD_EG2_CK>; + clock-names = "bus_ck", + "26m_ck", + "l_ck", + "aud_ck", + "eg2_ck"; + assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>, + <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL2_D4>; + }; + +... -- cgit v1.2.3 From a9b5f21073c0c687068f17e23385ec43fc643b08 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:17 +0200 Subject: ASoC: rt5640: Convert to just use GPIO descriptors The RT5640 driver is already using GPIO descriptors for some stuff, all that is needed is to convert the remaining LDO1 control line to also use descriptors. Simplify the code using gpiod_get_optional() and drop the special "of" parsing function: these descriptors need not come from device tree and it's optional so hey. Keep some NULL checks around the GPIO operations even though gpiolib is essentially NULL-tolerant, because by checking for whether we have a valid GPIO descriptor or not we can avoid a 400 ms delay which is great. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-1-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 55 +++++++++++++---------------------------------- sound/soc/codecs/rt5640.h | 2 +- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index eceed8209787..8920726c38e8 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -12,11 +12,10 @@ #include #include #include -#include +#include #include #include #include -#include #include #include #include @@ -2812,8 +2811,8 @@ static int rt5640_suspend(struct snd_soc_component *component) rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); - if (gpio_is_valid(rt5640->ldo1_en)) - gpio_set_value_cansleep(rt5640->ldo1_en, 0); + if (rt5640->ldo1_en) + gpiod_set_value_cansleep(rt5640->ldo1_en, 0); return 0; } @@ -2822,8 +2821,8 @@ static int rt5640_resume(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(rt5640->ldo1_en)) { - gpio_set_value_cansleep(rt5640->ldo1_en, 1); + if (rt5640->ldo1_en) { + gpiod_set_value_cansleep(rt5640->ldo1_en, 1); msleep(400); } @@ -2986,22 +2985,6 @@ static const struct acpi_device_id rt5640_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); #endif -static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) -{ - rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0); - /* - * LDO1_EN is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5640->ldo1_en) && - (rt5640->ldo1_en != -ENOENT)) - return rt5640->ldo1_en; - - return 0; -} - static int rt5640_i2c_probe(struct i2c_client *i2c) { struct rt5640_priv *rt5640; @@ -3015,12 +2998,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return -ENOMEM; i2c_set_clientdata(i2c, rt5640); - if (i2c->dev.of_node) { - ret = rt5640_parse_dt(rt5640, i2c->dev.of_node); - if (ret) - return ret; - } else - rt5640->ldo1_en = -EINVAL; + rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5640->ldo1_en)) + return PTR_ERR(rt5640->ldo1_en); + + if (rt5640->ldo1_en) { + gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN"); + msleep(400); + } rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); if (IS_ERR(rt5640->regmap)) { @@ -3030,18 +3017,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5640->ldo1_en)) { - ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en, - GPIOF_OUT_INIT_HIGH, - "RT5640 LDO1_EN"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n", - rt5640->ldo1_en, ret); - return ret; - } - msleep(400); - } - regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9847a1ae01f4..94b9a502f7f9 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2138,7 +2138,7 @@ struct rt5640_priv { struct regmap *regmap; struct clk *mclk; - int ldo1_en; /* GPIO for LDO1_EN */ + struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */ int irq; int jd_gpio_irq; int sysclk; -- cgit v1.2.3 From 647a3c4c33cd2c3902cdc07c50f3129166d715f5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:18 +0200 Subject: ASoC: rt5665: Convert to use GPIO descriptors The RT5665 driver has some stub support for GPIO descriptors going back to the initial driver commit, where there are two GPIO descriptors for the LDO and headphone detection defined in the device state. Well, let's make use of the descriptor properly. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-2-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- include/sound/rt5665.h | 2 -- sound/soc/codecs/rt5665.c | 17 ++++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/sound/rt5665.h b/include/sound/rt5665.h index 3b3d6a19ca49..e865f041929b 100644 --- a/include/sound/rt5665.h +++ b/include/sound/rt5665.h @@ -31,8 +31,6 @@ struct rt5665_platform_data { bool in3_diff; bool in4_diff; - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5665_dmic1_data_pin dmic1_data_pin; enum rt5665_dmic2_data_pin dmic2_data_pin; enum rt5665_jd_src jd_src; diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 525713c33d71..a39de4a7df00 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -4659,9 +4658,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5665->pdata.jd_src); - rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -4795,10 +4791,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5665->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5665")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + + rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5665->gpiod_ldo1_en)) { + dev_err(&i2c->dev, "Failed gpio request ldo1_en\n"); + return PTR_ERR(rt5665->gpiod_ldo1_en); } /* Sleep for 300 ms miniumum */ -- cgit v1.2.3 From ab2a5d17064436585807f2ece5e6b4b03769a11f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:19 +0200 Subject: ASoC: rt5668: Convert to use GPIO descriptors Convert the RT5668 to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-3-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- include/sound/rt5668.h | 3 --- sound/soc/codecs/rt5668.c | 17 ++++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/sound/rt5668.h b/include/sound/rt5668.h index 182edfbc9e7a..b682418c6cd6 100644 --- a/include/sound/rt5668.h +++ b/include/sound/rt5668.h @@ -25,9 +25,6 @@ enum rt5668_jd_src { }; struct rt5668_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5668_dmic1_data_pin dmic1_data_pin; enum rt5668_dmic1_clk_pin dmic1_clk_pin; enum rt5668_jd_src jd_src; diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index f04c810fd710..4623b3e62487 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = { struct rt5668_priv { struct snd_soc_component *component; struct rt5668_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES]; @@ -2393,9 +2393,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5668->pdata.jd_src); - rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -2497,10 +2494,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5668->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5668")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5668->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5668->ldo1_en); } /* Sleep for 300 ms miniumum */ -- cgit v1.2.3 From ed11701751d43fb2318c625e65e0507b5234f8a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:20 +0200 Subject: ASoC: rt5682: Convert to use GPIO descriptors Convert the RT5682 to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Make sure to make sure SDW devices can associate with an LDO1 EN descriptor too, if they so desire by putting the lookup into the common code. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-4-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- include/sound/rt5682.h | 3 --- sound/soc/codecs/rt5682-i2c.c | 11 ++++------- sound/soc/codecs/rt5682-sdw.c | 5 +++++ sound/soc/codecs/rt5682.c | 20 +++++++++++++++----- sound/soc/codecs/rt5682.h | 3 +++ 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h index 3900a07e3935..4256df721e3a 100644 --- a/include/sound/rt5682.h +++ b/include/sound/rt5682.h @@ -31,9 +31,6 @@ enum rt5682_dai_clks { }; struct rt5682_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5682_dmic1_data_pin dmic1_data_pin; enum rt5682_dmic1_clk_pin dmic1_clk_pin; enum rt5682_jd_src jd_src; diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index fb8ffb5b2ff6..b05b4f73d8aa 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -170,11 +169,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); - } + ret = rt5682_get_ldo1(rt5682, &i2c->dev); + if (ret) + return ret; /* Sleep for 300 ms miniumum */ usleep_range(300000, 350000); diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 65e9c6dc1a54..e67c2e19cb1a 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -320,6 +320,11 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, return ret; } + + ret = rt5682_get_ldo1(rt5682, dev); + if (ret) + return ret; + regcache_cache_only(rt5682->sdw_regmap, true); regcache_cache_only(rt5682->regmap, true); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 694c581070d9..e3aca9c785a0 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -3094,9 +3093,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) device_property_read_u32(dev, "realtek,dmic-delay-ms", &rt5682->pdata.dmic_delay); - rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682->pdata.dai_clk_names, RT5682_DAI_NUM_CLKS) < 0) @@ -3111,6 +3107,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) } EXPORT_SYMBOL_GPL(rt5682_parse_dt); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev) +{ + rt5682->ldo1_en = devm_gpiod_get_optional(dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682->ldo1_en)) { + dev_err(dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682->ldo1_en); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5682_get_ldo1); + void rt5682_calibrate(struct rt5682_priv *rt5682) { int value, count; diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 1a43d595f341..b2d9e87af259 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1430,6 +1431,7 @@ struct rt5682_priv { struct snd_soc_component *component; struct device *i2c_dev; struct rt5682_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct regmap *sdw_regmap; struct snd_soc_jack *hs_jack; @@ -1481,6 +1483,7 @@ int rt5682_register_component(struct device *dev); void rt5682_calibrate(struct rt5682_priv *rt5682); void rt5682_reset(struct rt5682_priv *rt5682); int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev); int rt5682_register_dai_clks(struct rt5682_priv *rt5682); -- cgit v1.2.3 From 8793bee716452e5e2f9bf085fbe01f9e3d1e659f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:21 +0200 Subject: ASoC: rt5682s: Convert to use GPIO descriptors Convert the RT5682S to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-5-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- include/sound/rt5682s.h | 3 --- sound/soc/codecs/rt5682s.c | 16 +++++++--------- sound/soc/codecs/rt5682s.h | 2 ++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h index f18d91308b9a..66ca0c75b914 100644 --- a/include/sound/rt5682s.h +++ b/include/sound/rt5682s.h @@ -32,9 +32,6 @@ enum rt5682s_dai_clks { }; struct rt5682s_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5682s_dmic1_data_pin dmic1_data_pin; enum rt5682s_dmic1_clk_pin dmic1_clk_pin; enum rt5682s_jd_src jd_src; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c77c675bd5f5..68ac5ea50396 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -2973,9 +2972,6 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) device_property_read_u32(dev, "realtek,amic-delay-ms", &rt5682s->pdata.amic_delay); - rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682s->pdata.dai_clk_names, RT5682S_DAI_NUM_CLKS) < 0) @@ -3172,10 +3168,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682s")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682s->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682s->ldo1_en); } /* Sleep for 50 ms minimum */ diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index caa7733b430f..1d79d432d0d8 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1446,6 +1447,7 @@ enum { struct rt5682s_priv { struct snd_soc_component *component; struct rt5682s_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES]; -- cgit v1.2.3 From aa98697c7dbd8dcb30841ca48456e7d534209d6d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 18 Aug 2023 02:37:32 +0000 Subject: ASoC: rt5645: improve the depop sequences of CBJ detection This patch will improve the depop function of CBJ detection before the headphone playback when the system resumes. We also want to complete the CBJ detection in the system-level resume function. It could avoid triggering the detection at the playing state of headphones. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20230818023732.2153170-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e49aa28280e0..038d93e20883 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -80,6 +80,7 @@ static const struct reg_sequence init_list[] = { static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, + {RT5645_PWR_ANLG1, 0x02}, }; static const struct reg_default rt5645_reg[] = { @@ -1696,6 +1697,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on) regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, + RT5645_PWR_HP_L | RT5645_PWR_HP_R); msleep(90); } else { /* depop parameters */ @@ -1743,7 +1747,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on) snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); msleep(100); snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001); - + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0); } else { snd_soc_component_update_bits(component, RT5645_DEPOP_M1, RT5645_HP_SG_MASK | @@ -3150,7 +3155,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse unsigned int val; if (jack_insert) { - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206); /* for jack type detect */ snd_soc_dapm_force_enable_pin(dapm, "LDO2"); @@ -3195,6 +3200,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse if (rt5645->pdata.level_trigger_irq) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); + + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); } else { /* jack out */ rt5645->jack_type = 0; @@ -4003,13 +4010,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c) regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080); - ret = regmap_register_patch(rt5645->regmap, init_list, + ret = regmap_multi_reg_write(rt5645->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); if (rt5645->codec_type == CODEC_TYPE_RT5650) { - ret = regmap_register_patch(rt5645->regmap, rt5650_init_list, + ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list, ARRAY_SIZE(rt5650_init_list)); if (ret != 0) dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n", @@ -4220,8 +4227,7 @@ static int __maybe_unused rt5645_sys_resume(struct device *dev) if (rt5645->hp_jack) { rt5645->jack_type = 0; - queue_delayed_work(system_power_efficient_wq, - &rt5645->jack_detect_work, msecs_to_jiffies(0)); + rt5645_jack_detect_work(&rt5645->jack_detect_work.work); } return 0; } -- cgit v1.2.3 From 919a4a941863c539e982d34903e93d9777316f7d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Fri, 18 Aug 2023 11:03:14 +0300 Subject: ASoC: amd: acp: Add kcontrols and widgets per-codec in common code Commit 7ac3404c2e21 ("ASoC: amd: acp: Map missing jack kcontrols") adds card kcontrols and DAPM widgets corresponding to jacks for Headphone and Headset Mic. But these were already being added in acp-legacy-mach.c and acp-sof-mach.c, so this causes a probe error: sof_mach rt5682s-hs-rt1019: control 2:0:0:Headphone Jack Switch:0 is already present sof_mach rt5682s-hs-rt1019: ASoC: Failed to add Headphone Jack Switch: -16 sof_mach rt5682s-hs-rt1019: devm_snd_soc_register_card(sof-rt5682s-hs-rt1019) failed: -16 sof_mach: probe of rt5682s-hs-rt1019 failed with error -16 Removing the new duplicates from the common code might be enough to fix the issue. But some of the codecs use different kcontrols and widgets. NAU8821 alone has an "Int Mic". MAX98360A has a single "Spk", while RT1019 has "Left Spk" and "Right Spk" (and two codec instances with name prefixes). Since there are per-codec differences, add the kcontrols and widgets in the common code as each dai-link is being initialized, instead of in the two machine drivers' probe(). Also, MAX98388 has Left and Right instances, but uses a single "SPK" widget. That seems weird, so normalize it to use two widgets (one per each instance like RT1019) while we're adding controls. Fixes: 7ac3404c2e21 ("ASoC: amd: acp: Map missing jack kcontrols") Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230818080314.32991-1-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-legacy-mach.c | 22 +----------- sound/soc/amd/acp/acp-mach-common.c | 68 +++++++++++++++++++++++++++++++++++-- sound/soc/amd/acp/acp-sof-mach.c | 21 +----------- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 676ad50638d0..6d57d17ddfd7 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -75,23 +75,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -110,11 +93,8 @@ static int acp_asoc_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index f3abaa182fbb..a06af82b8056 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -513,6 +513,16 @@ SND_SOC_DAILINK_DEF(rt1019, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"), COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); +static const struct snd_kcontrol_new rt1019_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget rt1019_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + static const struct snd_soc_dapm_route rt1019_map_lr[] = { { "Left Spk", NULL, "Left SPO" }, { "Right Spk", NULL, "Right SPO" }, @@ -533,10 +543,25 @@ static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; + int ret; if (drvdata->amp_codec_id != RT1019) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets, + ARRAY_SIZE(rt1019_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt1019_controls, + ARRAY_SIZE(rt1019_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr, ARRAY_SIZE(rt1019_map_lr)); } @@ -667,6 +692,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = { SND_SOC_DAILINK_DEF(max98360a, DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); +static const struct snd_kcontrol_new max98360a_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget max98360a_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + static const struct snd_soc_dapm_route max98360a_map[] = { {"Spk", NULL, "Speaker"}, }; @@ -675,10 +708,25 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; + int ret; if (drvdata->amp_codec_id != MAX98360A) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets, + ARRAY_SIZE(max98360a_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, max98360a_controls, + ARRAY_SIZE(max98360a_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map, ARRAY_SIZE(max98360a_map)); } @@ -744,13 +792,19 @@ SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"), COMP_CODEC("i2c-ADS8388:01", "max98388-aif1"))); +static const struct snd_kcontrol_new max98388_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + static const struct snd_soc_dapm_widget max98388_widgets[] = { - SND_SOC_DAPM_SPK("SPK", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), }; static const struct snd_soc_dapm_route max98388_map[] = { - { "SPK", NULL, "Left BE_OUT" }, - { "SPK", NULL, "Right BE_OUT" }, + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, }; static struct snd_soc_codec_conf max98388_conf[] = { @@ -803,6 +857,14 @@ static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd) /* Don't need to add routes if widget addition failed */ return ret; } + + ret = snd_soc_add_card_controls(card, max98388_controls, + ARRAY_SIZE(max98388_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map, ARRAY_SIZE(max98388_map)); } diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index a1c893f33f74..5223033a122f 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -94,22 +94,6 @@ static struct acp_card_drvdata sof_nau8821_max98388_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - static int acp_sof_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -128,11 +112,8 @@ static int acp_sof_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); -- cgit v1.2.3 From fc918cbe874eee0950b6425c1b30bcd4860dc076 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Aug 2023 11:46:02 +0100 Subject: ASoC: cs42l43: Add support for the cs42l43 The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed for portable applications. It provides a high dynamic range, stereo DAC for headphone output, two integrated Class D amplifiers for loudspeakers, and two ADCs for wired headset microphone input or stereo line input. PDM inputs are provided for digital microphones. The ASoC component provides the majority of the functionality of the device, all the audio functions. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs42l43.h | 17 + sound/soc/codecs/Kconfig | 16 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/cs42l43-jack.c | 946 ++++++++++++++++ sound/soc/codecs/cs42l43-sdw.c | 74 ++ sound/soc/codecs/cs42l43.c | 2278 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs42l43.h | 131 +++ 7 files changed, 3466 insertions(+) create mode 100644 include/sound/cs42l43.h create mode 100644 sound/soc/codecs/cs42l43-jack.c create mode 100644 sound/soc/codecs/cs42l43-sdw.c create mode 100644 sound/soc/codecs/cs42l43.c create mode 100644 sound/soc/codecs/cs42l43.h diff --git a/include/sound/cs42l43.h b/include/sound/cs42l43.h new file mode 100644 index 000000000000..deb337fc4e8c --- /dev/null +++ b/include/sound/cs42l43.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS42L43 CODEC driver external data + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef CS42L43_ASOC_EXT_H +#define CS42L43_ASOC_EXT_H + +#define CS42L43_SYSCLK 0 + +#define CS42L43_SYSCLK_MCLK 0 +#define CS42L43_SYSCLK_SDW 1 + +#endif /* CS42L43_ASOC_EXT_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c2de4ee72183..49367d49b416 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -74,6 +74,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L56_SDW imply SND_SOC_CS42L42 imply SND_SOC_CS42L42_SDW + imply SND_SOC_CS42L43 + imply SND_SOC_CS42L43_SDW imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 imply SND_SOC_CS42L56 @@ -789,6 +791,20 @@ config SND_SOC_CS42L42_SDW help Enable support for Cirrus Logic CS42L42 codec with Soundwire control +config SND_SOC_CS42L43 + tristate "Cirrus Logic CS42L43 CODEC" + depends on MFD_CS42L43 + help + Select this to support the audio functions of the Cirrus Logic + CS42L43 PC CODEC. + +config SND_SOC_CS42L43_SDW + tristate "Cirrus Logic CS42L43 CODEC (SoundWire)" + depends on SND_SOC_CS42L43 && MFD_CS42L43_SDW + help + Select this to support the audio functions of the Cirrus Logic + CS42L43 PC CODEC over SoundWire. + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b48a9a323b84..20d1a841991d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -75,6 +75,8 @@ snd-soc-cs35l56-sdw-objs := cs35l56-sdw.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o snd-soc-cs42l42-sdw-objs := cs42l42-sdw.o +snd-soc-cs42l43-objs := cs42l43.o cs42l43-jack.o +snd-soc-cs42l43-sdw-objs := cs42l43-sdw.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -457,6 +459,8 @@ obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o +obj-$(CONFIG_SND_SOC_CS42L43) += snd-soc-cs42l43.o +obj-$(CONFIG_SND_SOC_CS42L43_SDW) += snd-soc-cs42l43-sdw.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c new file mode 100644 index 000000000000..92e37bc1df9d --- /dev/null +++ b/sound/soc/codecs/cs42l43-jack.c @@ -0,0 +1,946 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver jack handling +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +static const unsigned int cs42l43_accdet_us[] = { + 20, 100, 1000, 10000, 50000, 75000, 100000, 200000 +}; + +static const unsigned int cs42l43_accdet_db_ms[] = { + 0, 125, 250, 500, 750, 1000, 1250, 1500 +}; + +static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 }; + +static const unsigned int cs42l43_accdet_bias_sense[] = { + 14, 23, 41, 50, 60, 68, 86, 95, 0, +}; + +static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop, + unsigned int defval, unsigned int *val, + const unsigned int *values, const int nvalues) +{ + struct cs42l43 *cs42l43 = priv->core; + int i, ret; + + ret = device_property_read_u32(cs42l43->dev, prop, &defval); + if (ret != -EINVAL && ret < 0) { + dev_err(priv->dev, "Property %s malformed: %d\n", prop, ret); + return ret; + } + + if (val) + *val = defval; + + for (i = 0; i < nvalues; i++) + if (defval == values[i]) + return i; + + dev_err(priv->dev, "Invalid value for property %s: %d\n", prop, defval); + return -EINVAL; +} + +int cs42l43_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *d) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + /* This tip sense invert is always set, HW wants an inverted signal */ + unsigned int tip_deb = CS42L43_TIPSENSE_INV_MASK; + unsigned int hs2 = 0x2 << CS42L43_HSDET_MODE_SHIFT; + unsigned int autocontrol = 0, pdncntl = 0; + int ret; + + dev_dbg(priv->dev, "Configure accessory detect\n"); + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret); + return ret; + } + + mutex_lock(&priv->jack_lock); + + priv->jack_hp = jack; + + if (!jack) + goto done; + + ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms"); + if (ret != -EINVAL) { + if (ret < 0) { + dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n", + ret); + goto error; + } + + if (ret > CS42L43_N_BUTTONS) { + ret = -EINVAL; + dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n"); + goto error; + } + + device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms", + priv->buttons, ret); + } else { + priv->buttons[0] = 70; + priv->buttons[1] = 185; + priv->buttons[2] = 355; + priv->buttons[3] = 735; + } + + ret = cs42l43_find_index(priv, "cirrus,detect-us", 10000, &priv->detect_us, + cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us)); + if (ret < 0) + goto error; + + hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT; + + priv->bias_low = device_property_read_bool(cs42l43->dev, "cirrus,bias-low"); + + ret = cs42l43_find_index(priv, "cirrus,bias-ramp-ms", 170, + &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms, + ARRAY_SIZE(cs42l43_accdet_ramp_ms)); + if (ret < 0) + goto error; + + hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,bias-sense-microamp", 0, + &priv->bias_sense_ua, cs42l43_accdet_bias_sense, + ARRAY_SIZE(cs42l43_accdet_bias_sense)); + if (ret < 0) + goto error; + + if (priv->bias_sense_ua) + autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT; + + if (!device_property_read_bool(cs42l43->dev, "cirrus,button-automute")) + autocontrol |= CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK; + + ret = device_property_read_u32(cs42l43->dev, "cirrus,tip-debounce-ms", + &priv->tip_debounce_ms); + if (ret < 0 && ret != -EINVAL) { + dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret); + goto error; + } + + /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */ + if (device_property_read_bool(cs42l43->dev, "cirrus,tip-invert")) + autocontrol |= 0x1 << CS42L43_JACKDET_INV_SHIFT; + + if (device_property_read_bool(cs42l43->dev, "cirrus,tip-disable-pullup")) + autocontrol |= 0x1 << CS42L43_JACKDET_MODE_SHIFT; + else + autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT; + + if (device_property_read_bool(cs42l43->dev, "cirrus,use-ring-sense")) { + unsigned int ring_deb = 0; + + priv->use_ring_sense = true; + + /* HW wants an inverted signal, so invert the invert */ + if (!device_property_read_bool(cs42l43->dev, "cirrus,ring-invert")) + ring_deb |= CS42L43_RINGSENSE_INV_MASK; + + if (!device_property_read_bool(cs42l43->dev, + "cirrus,ring-disable-pullup")) + ring_deb |= CS42L43_RINGSENSE_PULLUP_PDNB_MASK; + + ret = cs42l43_find_index(priv, "cirrus,ring-fall-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,ring-rise-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT; + pdncntl |= CS42L43_RING_SENSE_EN_MASK; + + regmap_update_bits(cs42l43->regmap, CS42L43_RINGSENSE_DEB_CTRL, + CS42L43_RINGSENSE_INV_MASK | + CS42L43_RINGSENSE_PULLUP_PDNB_MASK | + CS42L43_RINGSENSE_FALLING_DB_TIME_MASK | + CS42L43_RINGSENSE_RISING_DB_TIME_MASK, + ring_deb); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_TIPSENSE_DEB_CTRL, + CS42L43_TIPSENSE_INV_MASK | + CS42L43_TIPSENSE_FALLING_DB_TIME_MASK | + CS42L43_TIPSENSE_RISING_DB_TIME_MASK, tip_deb); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK | + CS42L43_AUTO_HSDET_TIME_MASK, hs2); + +done: + ret = 0; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | + CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); + regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, + CS42L43_RING_SENSE_EN_MASK, pdncntl); + + dev_dbg(priv->dev, "Successfully configured accessory detect\n"); + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; +} + +static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT; + + dev_dbg(priv->dev, "Start headset bias\n"); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK); + + if (!force_high && priv->bias_low) + val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT; + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, val); + + msleep(priv->bias_ramp_ms); +} + +static void cs42l43_stop_hs_bias(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop headset bias\n"); + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, 0); +} + +irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + queue_delayed_work(system_wq, &priv->bias_sense_timeout, + msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +#define CS42L43_JACK_PRESENT 0x3 +#define CS42L43_JACK_ABSENT 0x0 + +#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT) +#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE) +#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET) +#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT) +#define CS42L43_JACK_LINEIN (SND_JACK_MECHANICAL | SND_JACK_LINEIN) +#define CS42L43_JACK_EXTENSION (SND_JACK_MECHANICAL) +#define CS42L43_JACK_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | \ + SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5) + +static inline bool cs42l43_jack_present(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int sts = 0; + + regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts); + + sts = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + + return sts == CS42L43_JACK_PRESENT; +} + +static void cs42l43_start_button_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0x3 << CS42L43_BUTTON_DETECT_MODE_SHIFT; + + dev_dbg(priv->dev, "Start button detect\n"); + + priv->button_detect_running = true; + + if (priv->bias_low) + val = 0x1 << CS42L43_BUTTON_DETECT_MODE_SHIFT; + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_BUTTON_DETECT_MODE_MASK | + CS42L43_MIC_LVL_DET_DISABLE_MASK, val); + + if (priv->bias_sense_ua) { + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); + } +} + +static void cs42l43_stop_button_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop button detect\n"); + + if (priv->bias_sense_ua) { + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_BUTTON_DETECT_MODE_MASK | + CS42L43_MIC_LVL_DET_DISABLE_MASK, + CS42L43_MIC_LVL_DET_DISABLE_MASK); + + priv->button_detect_running = false; +} + +#define CS42L43_BUTTON_COMB_MAX 512 +#define CS42L43_BUTTON_ROUT 2210 + +void cs42l43_button_press_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + button_press_work.work); + struct cs42l43 *cs42l43 = priv->core; + unsigned int buttons = 0; + unsigned int val = 0; + int i, ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for button press: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (!priv->button_detect_running) { + dev_dbg(priv->dev, "Spurious button press IRQ\n"); + goto error; + } + + regmap_read(cs42l43->regmap, CS42L43_DETECT_STATUS_1, &val); + + /* Bail if jack removed, the button is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) { + dev_dbg(priv->dev, "Button ignored due to removal\n"); + goto error; + } + + if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) { + dev_dbg(priv->dev, "Button ignored due to bias sense\n"); + goto error; + } + + val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT; + val = ((CS42L43_BUTTON_COMB_MAX << 20) / (val + 1)) - (1 << 20); + if (val) + val = (CS42L43_BUTTON_ROUT << 20) / val; + else + val = UINT_MAX; + + for (i = 0; i < CS42L43_N_BUTTONS; i++) { + if (val < priv->buttons[i]) { + buttons = SND_JACK_BTN_0 >> i; + dev_dbg(priv->dev, "Detected button %d at %d Ohms\n", i, val); + break; + } + } + + if (!buttons) + dev_dbg(priv->dev, "Unrecognised button: %d Ohms\n", val); + + snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS); + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_button_press(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + // Wait for 2 full cycles of comb filter to ensure good reading + queue_delayed_work(system_wq, &priv->button_press_work, + msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +void cs42l43_button_release_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + button_release_work); + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for button release: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (priv->button_detect_running) { + dev_dbg(priv->dev, "Button release IRQ\n"); + + snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); + } else { + dev_dbg(priv->dev, "Spurious button release IRQ\n"); + } + + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_button_release(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + queue_work(system_wq, &priv->button_release_work); + + return IRQ_HANDLED; +} + +void cs42l43_bias_sense_timeout(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + bias_sense_timeout.work); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (cs42l43_jack_present(priv) && priv->button_detect_running) { + dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n"); + + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); + } + + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +static void cs42l43_start_load_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Start load detect\n"); + + snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component)); + + priv->load_detect_running = true; + + if (priv->hp_ena) { + unsigned long time_left; + + reinit_completion(&priv->hp_shutdown); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + CS42L43_HP_EN_MASK, 0); + + time_left = wait_for_completion_timeout(&priv->hp_shutdown, + msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS)); + if (!time_left) + dev_err(priv->dev, "Load detect HP power down timed out\n"); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL, + CS42L43_ADPTPWR_MODE_MASK, 0x4 << CS42L43_ADPTPWR_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL, + CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, 0x6); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, 0); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA, + CS42L43_HPLOAD_DET_EN_MASK, + CS42L43_HPLOAD_DET_EN_MASK); + + snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component)); +} + +static void cs42l43_stop_load_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop load detect\n"); + + snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component)); + + regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA, + CS42L43_HPLOAD_DET_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL, + CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, + 0x4 << CS42L43_HP_DIG_VOL_RAMP_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL, + CS42L43_ADPTPWR_MODE_MASK, 0x7 << CS42L43_ADPTPWR_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, + CS42L43_HP_HPF_EN_MASK, CS42L43_HP_HPF_EN_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, + priv->adc_ena); + + if (priv->hp_ena) { + unsigned long time_left; + + reinit_completion(&priv->hp_startup); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + CS42L43_HP_EN_MASK, priv->hp_ena); + + time_left = wait_for_completion_timeout(&priv->hp_startup, + msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS)); + if (!time_left) + dev_err(priv->dev, "Load detect HP restore timed out\n"); + } + + priv->load_detect_running = false; + + snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component)); +} + +static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0; + unsigned long time_left; + + reinit_completion(&priv->load_detect); + + cs42l43_start_load_detect(priv); + time_left = wait_for_completion_timeout(&priv->load_detect, + msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS)); + cs42l43_stop_load_detect(priv); + + if (!time_left) + return -ETIMEDOUT; + + regmap_read(cs42l43->regmap, CS42L43_LOADDETRESULTS, &val); + + dev_dbg(priv->dev, "Headphone load detect: 0x%x\n", val); + + /* Bail if jack removed, the load is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) + return -ENODEV; + + if (mic) { + cs42l43_start_hs_bias(priv, false); + cs42l43_start_button_detect(priv); + + return CS42L43_JACK_HEADSET; + } + + switch (val & CS42L43_AMP3_RES_DET_MASK) { + case 0x0: // low impedance + case 0x1: // high impedance + return CS42L43_JACK_HEADPHONE; + case 0x2: // lineout + case 0x3: // Open circuit + return CS42L43_JACK_LINEOUT; + default: + return -EINVAL; + } +} + +static int cs42l43_run_type_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + int timeout_ms = ((2 * priv->detect_us) / 1000) + 200; + unsigned int type = 0xff; + unsigned long time_left; + + reinit_completion(&priv->type_detect); + + cs42l43_start_hs_bias(priv, true); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT); + + time_left = wait_for_completion_timeout(&priv->type_detect, + msecs_to_jiffies(timeout_ms)); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); + cs42l43_stop_hs_bias(priv); + + if (!time_left) + return -ETIMEDOUT; + + regmap_read(cs42l43->regmap, CS42L43_HS_STAT, &type); + + dev_dbg(priv->dev, "Type detect: 0x%x\n", type); + + /* Bail if jack removed, the type is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) + return -ENODEV; + + switch (type & CS42L43_HSDET_TYPE_STS_MASK) { + case 0x0: // CTIA + case 0x1: // OMTP + return cs42l43_run_load_detect(priv, true); + case 0x2: // 3-pole + return cs42l43_run_load_detect(priv, false); + case 0x3: // Open-circuit + return CS42L43_JACK_EXTENSION; + default: + return -EINVAL; + } +} + +static void cs42l43_clear_jack(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + cs42l43_stop_button_detect(priv); + cs42l43_stop_hs_bias(priv); + + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL, + CS42L43_JACK_STEREO_CONFIG_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK, + 0x2 << CS42L43_HSDET_MODE_SHIFT); + + snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF); +} + +void cs42l43_tip_sense_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + tip_sense_work.work); + struct cs42l43 *cs42l43 = priv->core; + unsigned int sts = 0; + unsigned int tip, ring; + int ret, report; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for tip work: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts); + + dev_dbg(priv->dev, "Tip sense: 0x%x\n", sts); + + tip = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + ring = (sts >> CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + + if (tip == CS42L43_JACK_PRESENT) { + if (cs42l43->sdw && !priv->jack_present) { + priv->jack_present = true; + pm_runtime_get(priv->dev); + } + + if (priv->use_ring_sense && ring == CS42L43_JACK_ABSENT) { + report = CS42L43_JACK_OPTICAL; + } else { + report = cs42l43_run_type_detect(priv); + if (report < 0) { + dev_err(priv->dev, "Jack detect failed: %d\n", report); + goto error; + } + } + + snd_soc_jack_report(priv->jack_hp, report, report); + } else { + priv->jack_override = 0; + + cs42l43_clear_jack(priv); + + if (cs42l43->sdw && priv->jack_present) { + pm_runtime_put(priv->dev); + priv->jack_present = false; + } + } + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_tip_sense(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + cancel_delayed_work(&priv->bias_sense_timeout); + cancel_delayed_work(&priv->tip_sense_work); + cancel_delayed_work(&priv->button_press_work); + cancel_work(&priv->button_release_work); + + queue_delayed_work(system_long_wq, &priv->tip_sense_work, + msecs_to_jiffies(priv->tip_debounce_ms)); + + return IRQ_HANDLED; +} + +enum cs42l43_raw_jack { + CS42L43_JACK_RAW_CTIA = 0, + CS42L43_JACK_RAW_OMTP, + CS42L43_JACK_RAW_HEADPHONE, + CS42L43_JACK_RAW_LINE_OUT, + CS42L43_JACK_RAW_LINE_IN, + CS42L43_JACK_RAW_MICROPHONE, + CS42L43_JACK_RAW_OPTICAL, +}; + +#define CS42L43_JACK_3_POLE_SWITCHES ((0x2 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | \ + CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | \ + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | \ + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | \ + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | \ + CS42L43_HSGND_HS3_SEL_MASK | \ + CS42L43_HSGND_HS4_SEL_MASK) + +static const struct cs42l43_jack_override_mode { + unsigned int hsdet_mode; + unsigned int mic_ctrl; + unsigned int clamp_ctrl; + int report; +} cs42l43_jack_override_modes[] = { + [CS42L43_JACK_RAW_CTIA] = { + .hsdet_mode = CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_OUT_HS4_SEL_MASK | + CS42L43_HSGND_HS3_SEL_MASK, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADSET, + }, + [CS42L43_JACK_RAW_OMTP] = { + .hsdet_mode = (0x1 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_OUT_HS3_SEL_MASK | + CS42L43_HSGND_HS4_SEL_MASK, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADSET, + }, + [CS42L43_JACK_RAW_HEADPHONE] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADPHONE, + }, + [CS42L43_JACK_RAW_LINE_OUT] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_LINEOUT, + }, + [CS42L43_JACK_RAW_LINE_IN] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .mic_ctrl = 0x2 << CS42L43_JACK_STEREO_CONFIG_SHIFT, + .report = CS42L43_JACK_LINEIN, + }, + [CS42L43_JACK_RAW_MICROPHONE] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) | + CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK, + .report = CS42L43_JACK_LINEIN, + }, + [CS42L43_JACK_RAW_OPTICAL] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_OPTICAL, + }, +}; + +static const char * const cs42l43_jack_text[] = { + "None", "CTIA", "OMTP", "Headphone", "Line-Out", + "Line-In", "Microphone", "Optical", +}; + +SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text); + +int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->jack_lock); + ucontrol->value.integer.value[0] = priv->jack_override; + mutex_unlock(&priv->jack_lock); + + return 0; +} + +int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int override = ucontrol->value.integer.value[0]; + + BUILD_BUG_ON(ARRAY_SIZE(cs42l43_jack_override_modes) != + ARRAY_SIZE(cs42l43_jack_text) - 1); + + if (override >= e->items) + return -EINVAL; + + mutex_lock(&priv->jack_lock); + + if (!cs42l43_jack_present(priv)) { + mutex_unlock(&priv->jack_lock); + return -EBUSY; + } + + if (override == priv->jack_override) { + mutex_unlock(&priv->jack_lock); + return 0; + } + + priv->jack_override = override; + + cs42l43_clear_jack(priv); + + if (!override) { + queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0); + } else { + override--; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK | + CS42L43_HSDET_MANUAL_MODE_MASK | + CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_OUT_HS3_SEL_MASK | + CS42L43_HSBIAS_OUT_HS4_SEL_MASK | + CS42L43_HSGND_HS3_SEL_MASK | + CS42L43_HSGND_HS4_SEL_MASK, + cs42l43_jack_override_modes[override].hsdet_mode); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL, + CS42L43_HS2_BIAS_EN_MASK | CS42L43_HS1_BIAS_EN_MASK | + CS42L43_JACK_STEREO_CONFIG_MASK, + cs42l43_jack_override_modes[override].mic_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, + CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + cs42l43_jack_override_modes[override].clamp_ctrl); + + switch (override) { + case CS42L43_JACK_RAW_CTIA: + case CS42L43_JACK_RAW_OMTP: + cs42l43_start_hs_bias(priv, false); + cs42l43_start_button_detect(priv); + break; + case CS42L43_JACK_RAW_LINE_IN: + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, + CS42L43_PGA_WIDESWING_MODE_EN_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, + CS42L43_PGA_WIDESWING_MODE_EN_MASK); + break; + case CS42L43_JACK_RAW_MICROPHONE: + cs42l43_start_hs_bias(priv, false); + break; + default: + break; + } + + snd_soc_jack_report(priv->jack_hp, + cs42l43_jack_override_modes[override].report, + cs42l43_jack_override_modes[override].report); + } + + mutex_unlock(&priv->jack_lock); + + return 1; +} diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c new file mode 100644 index 000000000000..55ac5fe8c3db --- /dev/null +++ b/sound/soc/codecs/cs42l43-sdw.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver SoundWire handling +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent); + struct sdw_stream_config sconfig = {0}; + struct sdw_port_config pconfig = {0}; + int ret; + + if (!sdw_stream) + return -EINVAL; + + snd_sdw_params_to_config(substream, params, &sconfig, &pconfig); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pconfig.num = dai->id; + else + pconfig.num = dai->id; + + ret = sdw_stream_add_slave(sdw, &sconfig, &pconfig, 1, sdw_stream); + if (ret) { + dev_err(priv->dev, "Failed to add sdw stream: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, SND_SOC_CS42L43); + +int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent); + + if (!sdw_stream) + return -EINVAL; + + return sdw_stream_remove_slave(sdw, sdw_stream); +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, SND_SOC_CS42L43); + +int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, SND_SOC_CS42L43); + +MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c new file mode 100644 index 000000000000..55a79219af35 --- /dev/null +++ b/sound/soc/codecs/cs42l43.c @@ -0,0 +1,2278 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +#define CS42L43_DECL_MUX(name, reg) \ +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \ + 0, CS42L43_MIXER_SRC_MASK, \ + cs42l43_mixer_texts, cs42l43_mixer_values); \ +static const struct snd_kcontrol_new cs42l43_##name##_mux = \ + SOC_DAPM_ENUM("Route", cs42l43_##name##_enum) + +#define CS42L43_DECL_MIXER(name, reg) \ + CS42L43_DECL_MUX(name##_in1, reg); \ + CS42L43_DECL_MUX(name##_in2, reg + 0x4); \ + CS42L43_DECL_MUX(name##_in3, reg + 0x8); \ + CS42L43_DECL_MUX(name##_in4, reg + 0xC) + +#define CS42L43_DAPM_MUX(name_str, name) \ + SND_SOC_DAPM_MUX(name_str " Input", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_mux) + +#define CS42L43_DAPM_MIXER(name_str, name) \ + SND_SOC_DAPM_MUX(name_str " Input 1", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in1_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 2", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in2_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 3", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in3_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 4", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in4_mux), \ + SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) + +#define CS42L43_BASE_ROUTES(name_str) \ + { name_str, "Tone Generator 1", "Tone 1" }, \ + { name_str, "Tone Generator 2", "Tone 2" }, \ + { name_str, "Decimator 1", "Decimator 1" }, \ + { name_str, "Decimator 2", "Decimator 2" }, \ + { name_str, "Decimator 3", "Decimator 3" }, \ + { name_str, "Decimator 4", "Decimator 4" }, \ + { name_str, "ASPRX1", "ASPRX1" }, \ + { name_str, "ASPRX2", "ASPRX2" }, \ + { name_str, "ASPRX3", "ASPRX3" }, \ + { name_str, "ASPRX4", "ASPRX4" }, \ + { name_str, "ASPRX5", "ASPRX5" }, \ + { name_str, "ASPRX6", "ASPRX6" }, \ + { name_str, "DP5RX1", "DP5RX1" }, \ + { name_str, "DP5RX2", "DP5RX2" }, \ + { name_str, "DP6RX1", "DP6RX1" }, \ + { name_str, "DP6RX2", "DP6RX2" }, \ + { name_str, "DP7RX1", "DP7RX1" }, \ + { name_str, "DP7RX2", "DP7RX2" }, \ + { name_str, "ASRC INT1", "ASRC_INT1" }, \ + { name_str, "ASRC INT2", "ASRC_INT2" }, \ + { name_str, "ASRC INT3", "ASRC_INT3" }, \ + { name_str, "ASRC INT4", "ASRC_INT4" }, \ + { name_str, "ASRC DEC1", "ASRC_DEC1" }, \ + { name_str, "ASRC DEC2", "ASRC_DEC2" }, \ + { name_str, "ASRC DEC3", "ASRC_DEC3" }, \ + { name_str, "ASRC DEC4", "ASRC_DEC4" }, \ + { name_str, "ISRC1 INT1", "ISRC1INT1" }, \ + { name_str, "ISRC1 INT2", "ISRC1INT2" }, \ + { name_str, "ISRC1 DEC1", "ISRC1DEC1" }, \ + { name_str, "ISRC1 DEC2", "ISRC1DEC2" }, \ + { name_str, "ISRC2 INT1", "ISRC2INT1" }, \ + { name_str, "ISRC2 INT2", "ISRC2INT2" }, \ + { name_str, "ISRC2 DEC1", "ISRC2DEC1" }, \ + { name_str, "ISRC2 DEC2", "ISRC2DEC2" }, \ + { name_str, "EQ1", "EQ" }, \ + { name_str, "EQ2", "EQ" } + +#define CS42L43_MUX_ROUTES(name_str, widget) \ + { widget, NULL, name_str " Input" }, \ + { name_str " Input", NULL, "Mixer Core" }, \ + CS42L43_BASE_ROUTES(name_str " Input") + +#define CS42L43_MIXER_ROUTES(name_str, widget) \ + { name_str " Mixer", NULL, name_str " Input 1" }, \ + { name_str " Mixer", NULL, name_str " Input 2" }, \ + { name_str " Mixer", NULL, name_str " Input 3" }, \ + { name_str " Mixer", NULL, name_str " Input 4" }, \ + { widget, NULL, name_str " Mixer" }, \ + { name_str " Mixer", NULL, "Mixer Core" }, \ + CS42L43_BASE_ROUTES(name_str " Input 1"), \ + CS42L43_BASE_ROUTES(name_str " Input 2"), \ + CS42L43_BASE_ROUTES(name_str " Input 3"), \ + CS42L43_BASE_ROUTES(name_str " Input 4") + +#define CS42L43_MIXER_VOLUMES(name_str, base) \ + SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume", base, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 2 Volume", base + 4, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 3 Volume", base + 8, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 4 Volume", base + 12, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv) + +#define CS42L43_IRQ_ERROR(name) \ +static irqreturn_t cs42l43_##name(int irq, void *data) \ +{ \ + struct cs42l43_codec *priv = data; \ + dev_err(priv->dev, "Error " #name " IRQ\n"); \ + return IRQ_HANDLED; \ +} + +CS42L43_IRQ_ERROR(pll_lost_lock) +CS42L43_IRQ_ERROR(spkr_clock_stop) +CS42L43_IRQ_ERROR(spkl_clock_stop) +CS42L43_IRQ_ERROR(spkr_brown_out) +CS42L43_IRQ_ERROR(spkl_brown_out) +CS42L43_IRQ_ERROR(spkr_therm_shutdown) +CS42L43_IRQ_ERROR(spkl_therm_shutdown) +CS42L43_IRQ_ERROR(spkr_therm_warm) +CS42L43_IRQ_ERROR(spkl_therm_warm) +CS42L43_IRQ_ERROR(spkr_sc_detect) +CS42L43_IRQ_ERROR(spkl_sc_detect) +CS42L43_IRQ_ERROR(hp_ilimit) + +#define CS42L43_IRQ_COMPLETE(name) \ +static irqreturn_t cs42l43_##name(int irq, void *data) \ +{ \ + struct cs42l43_codec *priv = data; \ + dev_dbg(priv->dev, #name " completed\n"); \ + complete(&priv->name); \ + return IRQ_HANDLED; \ +} + +CS42L43_IRQ_COMPLETE(pll_ready) +CS42L43_IRQ_COMPLETE(hp_startup) +CS42L43_IRQ_COMPLETE(hp_shutdown) +CS42L43_IRQ_COMPLETE(type_detect) +CS42L43_IRQ_COMPLETE(spkr_shutdown) +CS42L43_IRQ_COMPLETE(spkl_shutdown) +CS42L43_IRQ_COMPLETE(spkr_startup) +CS42L43_IRQ_COMPLETE(spkl_startup) +CS42L43_IRQ_COMPLETE(load_detect) + +static irqreturn_t cs42l43_mic_shutter(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + const char * const controls[] = { + "Decimator 1 Switch", + "Decimator 2 Switch", + "Decimator 3 Switch", + "Decimator 4 Switch", + }; + int i, ret; + + dev_dbg(priv->dev, "Microphone shutter changed\n"); + + if (!priv->component) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(controls); i++) { + ret = snd_soc_component_notify_control(priv->component, + controls[i]); + if (ret) + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static irqreturn_t cs42l43_spk_shutter(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + int ret; + + dev_dbg(priv->dev, "Speaker shutter changed\n"); + + if (!priv->component) + return IRQ_NONE; + + ret = snd_soc_component_notify_control(priv->component, + "Speaker Digital Switch"); + if (ret) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static const unsigned int cs42l43_sample_rates[] = { + 8000, 16000, 24000, 32000, 44100, 48000, 96000, 192000, +}; + +#define CS42L43_CONSUMER_RATE_MASK 0xFF +#define CS42L43_PROVIDER_RATE_MASK 0xEF // 44.1k only supported as consumer + +static const struct snd_pcm_hw_constraint_list cs42l43_constraint = { + .count = ARRAY_SIZE(cs42l43_sample_rates), + .list = cs42l43_sample_rates, +}; + +static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + + if (provider) + priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK; + else + priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK; + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &priv->constraint); +} + +static int cs42l43_convert_sample_rate(unsigned int rate) +{ + switch (rate) { + case 8000: + return 0x11; + case 16000: + return 0x12; + case 24000: + return 0x02; + case 32000: + return 0x13; + case 44100: + return 0x0B; + case 48000: + return 0x03; + case 96000: + return 0x04; + case 192000: + return 0x05; + default: + return -EINVAL; + } +} + +static int cs42l43_set_sample_rate(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + ret = cs42l43_convert_sample_rate(params_rate(params)); + if (ret < 0) { + dev_err(priv->dev, "Failed to convert sample rate: %d\n", ret); + return ret; + } + + //FIXME: For now lets just set sample rate 1, this needs expanded in the future + regmap_update_bits(cs42l43->regmap, CS42L43_SAMPLE_RATE1, + CS42L43_SAMPLE_RATE_MASK, ret); + + return 0; +} + +static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct cs42l43 *cs42l43 = priv->core; + int dsp_mode = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CTRL, + CS42L43_ASP_FSYNC_MODE_MASK); + int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + int n_chans = params_channels(params); + int data_width = params_width(params); + int n_slots = n_chans; + int slot_width = data_width; + int frame, bclk_target, i; + unsigned int reg; + int *slots; + + if (priv->n_slots) { + n_slots = priv->n_slots; + slot_width = priv->slot_width; + } + + if (!dsp_mode && (n_slots & 0x1)) { + dev_dbg(priv->dev, "Forcing balanced channels on ASP\n"); + n_slots++; + } + + frame = n_slots * slot_width; + bclk_target = params_rate(params) * frame; + + if (provider) { + unsigned int gcd_nm = gcd(bclk_target, CS42L43_INTERNAL_SYSCLK); + int n = bclk_target / gcd_nm; + int m = CS42L43_INTERNAL_SYSCLK / gcd_nm; + + if (n > (CS42L43_ASP_BCLK_N_MASK >> CS42L43_ASP_BCLK_N_SHIFT) || + m > CS42L43_ASP_BCLK_M_MASK) { + dev_err(priv->dev, "Can't produce %dHz bclk\n", bclk_target); + return -EINVAL; + } + + dev_dbg(priv->dev, "bclk %d/%d = %dHz, with %dx%d frame\n", + n, m, bclk_target, n_slots, slot_width); + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG1, + CS42L43_ASP_BCLK_N_MASK | CS42L43_ASP_BCLK_M_MASK, + n << CS42L43_ASP_BCLK_N_SHIFT | + m << CS42L43_ASP_BCLK_M_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL1, + CS42L43_ASP_FSYNC_M_MASK, frame); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL4, + CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK, + frame << CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + reg = CS42L43_ASP_TX_CH1_CTRL; + slots = priv->tx_slots; + } else { + reg = CS42L43_ASP_RX_CH1_CTRL; + slots = priv->rx_slots; + } + + for (i = 0; i < n_chans; i++, reg += 4) { + int slot_phase = dsp_mode | (i & CS42L43_ASP_CH_SLOT_PHASE_MASK); + int slot_pos; + + if (dsp_mode) + slot_pos = slots[i] * slot_width; + else + slot_pos = (slots[i] / 2) * slot_width; + + dev_dbg(priv->dev, "Configure channel %d at slot %d (%d,%d)\n", + i, slots[i], slot_pos, slot_phase); + + regmap_update_bits(cs42l43->regmap, reg, + CS42L43_ASP_CH_WIDTH_MASK | + CS42L43_ASP_CH_SLOT_MASK | + CS42L43_ASP_CH_SLOT_PHASE_MASK, + ((data_width - 1) << CS42L43_ASP_CH_WIDTH_SHIFT) | + (slot_pos << CS42L43_ASP_CH_SLOT_SHIFT) | + slot_phase); + } + + return cs42l43_set_sample_rate(substream, params, dai); +} + +static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + struct snd_soc_dapm_route routes[] = { + { "BCLK", NULL, "FSYNC" }, + }; + unsigned int asp_ctrl = 0; + unsigned int data_ctrl = 0; + unsigned int fsync_ctrl = 0; + unsigned int clk_config = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT; + fallthrough; + case SND_SOC_DAIFMT_DSP_B: + asp_ctrl |= CS42L43_ASP_FSYNC_MODE_MASK; + data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK; + break; + case SND_SOC_DAIFMT_I2S: + data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT; + break; + case SND_SOC_DAIFMT_LEFT_J: + data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK; + break; + default: + dev_err(priv->dev, "Unsupported DAI format 0x%x\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + if (provider) + snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes)); + break; + case SND_SOC_DAIFMT_CBP_CFP: + if (!provider) + snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes)); + clk_config |= CS42L43_ASP_MASTER_MODE_MASK; + break; + default: + dev_err(priv->dev, "Unsupported ASP mode 0x%x\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + clk_config |= CS42L43_ASP_BCLK_INV_MASK; /* Yes BCLK_INV = NB */ + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + clk_config |= CS42L43_ASP_BCLK_INV_MASK; + fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK; + break; + default: + dev_err(priv->dev, "Unsupported invert mode 0x%x\n", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CTRL, + CS42L43_ASP_FSYNC_MODE_MASK, + asp_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_DATA_CTRL, + CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK | + CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK, + data_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK | + CS42L43_ASP_BCLK_INV_MASK, + clk_config); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL3, + CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK, + fsync_ctrl); + + return 0; +} + +static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned int mask, int *slots) +{ + int i; + + for (i = 0; i < CS42L43_ASP_MAX_CHANNELS; ++i) { + int slot = ffs(mask) - 1; + + if (slot < 0) + return; + + slots[i] = slot; + + mask &= ~(1 << slot); + } + + if (mask) + dev_warn(priv->dev, "Too many channels in TDM mask\n"); +} + +static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + priv->n_slots = slots; + priv->slot_width = slot_width; + + if (!slots) { + tx_mask = CS42L43_DEFAULT_SLOTS; + rx_mask = CS42L43_DEFAULT_SLOTS; + } + + cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots); + cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots); + + return 0; +} + +static const struct snd_soc_dai_ops cs42l43_asp_ops = { + .startup = cs42l43_startup, + .hw_params = cs42l43_asp_hw_params, + .set_fmt = cs42l43_asp_set_fmt, + .set_tdm_slot = cs42l43_asp_set_tdm_slot, +}; + +static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int ret; + + ret = cs42l43_sdw_add_peripheral(substream, params, dai); + if (ret) + return ret; + + return cs42l43_set_sample_rate(substream, params, dai); +}; + +static const struct snd_soc_dai_ops cs42l43_sdw_ops = { + .startup = cs42l43_startup, + .set_stream = cs42l43_sdw_set_stream, + .hw_params = cs42l43_sdw_hw_params, + .hw_free = cs42l43_sdw_remove_peripheral, +}; + +#define CS42L43_ASP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +#define CS42L43_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver cs42l43_dais[] = { + { + .name = "cs42l43-asp", + .ops = &cs42l43_asp_ops, + .symmetric_rate = 1, + .capture = { + .stream_name = "ASP Capture", + .channels_min = 1, + .channels_max = CS42L43_ASP_MAX_CHANNELS, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_ASP_FORMATS, + }, + .playback = { + .stream_name = "ASP Playback", + .channels_min = 1, + .channels_max = CS42L43_ASP_MAX_CHANNELS, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_ASP_FORMATS, + }, + }, + { + .name = "cs42l43-dp1", + .id = 1, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp2", + .id = 2, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp3", + .id = 3, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp4", + .id = 4, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp5", + .id = 5, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP5 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp6", + .id = 6, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP6 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp7", + .id = 7, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP7 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, +}; + +static const DECLARE_TLV_DB_SCALE(cs42l43_mixer_tlv, -3200, 100, 0); + +static const char * const cs42l43_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +static const char * const cs42l43_adc1_input_text[] = { "IN1", "IN2" }; + +static SOC_ENUM_SINGLE_DECL(cs42l43_adc1_input, CS42L43_ADC_B_CTRL1, + CS42L43_ADC_AIN_SEL_SHIFT, + cs42l43_adc1_input_text); + +static const struct snd_kcontrol_new cs42l43_adc1_input_ctl = + SOC_DAPM_ENUM("ADC1 Input", cs42l43_adc1_input); + +static const char * const cs42l43_dec_mode_text[] = { "ADC", "PDM" }; + +static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec1_mode, cs42l43_dec_mode_text); +static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec2_mode, cs42l43_dec_mode_text); + +static const struct snd_kcontrol_new cs42l43_dec_mode_ctl[] = { + SOC_DAPM_ENUM("Decimator 1 Mode", cs42l43_dec1_mode), + SOC_DAPM_ENUM("Decimator 2 Mode", cs42l43_dec2_mode), +}; + +static const char * const cs42l43_pdm_clk_text[] = { + "3.072MHz", "1.536MHz", "768kHz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_pdm1_clk, CS42L43_PDM_CONTROL, + CS42L43_PDM1_CLK_DIV_SHIFT, cs42l43_pdm_clk_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_pdm2_clk, CS42L43_PDM_CONTROL, + CS42L43_PDM2_CLK_DIV_SHIFT, cs42l43_pdm_clk_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_adc_tlv, -600, 600, 0); +static DECLARE_TLV_DB_SCALE(cs42l43_dec_tlv, -6400, 50, 0); + +static const char * const cs42l43_wnf_corner_text[] = { + "160Hz", "180Hz", "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); + +static const char * const cs42l43_hpf_corner_text[] = { + "3Hz", "12Hz", "48Hz", "96Hz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0); + +static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP, + CS42L43_AMP1_2_VI_RAMP_SHIFT, cs42l43_ramp_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_down, CS42L43_AMP1_2_VOL_RAMP, + CS42L43_AMP1_2_VD_RAMP_SHIFT, cs42l43_ramp_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_headphone_tlv, -11450, 50, 1); + +static const char * const cs42l43_headphone_ramp_text[] = { + "1", "2", "4", "6", "8", "11", "12", "16", "22", "24", "33", "36", "44", + "48", "66", "72", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_headphone_ramp, CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_RAMP_SHIFT, + cs42l43_headphone_ramp_text); + +static const char * const cs42l43_tone_freq_text[] = { + "1kHz", "2kHz", "4kHz", "6kHz", "8kHz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_tone1_freq, CS42L43_TONE_CH1_CTRL, + CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_tone2_freq, CS42L43_TONE_CH2_CTRL, + CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text); + +static const char * const cs42l43_mixer_texts[] = { + "None", + "Tone Generator 1", "Tone Generator 2", + "Decimator 1", "Decimator 2", "Decimator 3", "Decimator 4", + "ASPRX1", "ASPRX2", "ASPRX3", "ASPRX4", "ASPRX5", "ASPRX6", + "DP5RX1", "DP5RX2", "DP6RX1", "DP6RX2", "DP7RX1", "DP7RX2", + "ASRC INT1", "ASRC INT2", "ASRC INT3", "ASRC INT4", + "ASRC DEC1", "ASRC DEC2", "ASRC DEC3", "ASRC DEC4", + "ISRC1 INT1", "ISRC1 INT2", + "ISRC1 DEC1", "ISRC1 DEC2", + "ISRC2 INT1", "ISRC2 INT2", + "ISRC2 DEC1", "ISRC2 DEC2", + "EQ1", "EQ2", +}; + +static const unsigned int cs42l43_mixer_values[] = { + 0x00, // None + 0x04, 0x05, // Tone Generator 1, 2 + 0x10, 0x11, 0x12, 0x13, // Decimator 1, 2, 3, 4 + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6 + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2 + 0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4 + 0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4 + 0x50, 0x51, // ISRC1 INT1, 2 + 0x52, 0x53, // ISRC1 DEC1, 2 + 0x54, 0x55, // ISRC2 INT1, 2 + 0x56, 0x57, // ISRC2 DEC1, 2 + 0x58, 0x59, // EQ1, 2 +}; + +CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT); +CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT); +CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT); +CS42L43_DECL_MUX(asptx4, CS42L43_ASPTX4_INPUT); +CS42L43_DECL_MUX(asptx5, CS42L43_ASPTX5_INPUT); +CS42L43_DECL_MUX(asptx6, CS42L43_ASPTX6_INPUT); + +CS42L43_DECL_MUX(dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT); +CS42L43_DECL_MUX(dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT); +CS42L43_DECL_MUX(dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT); +CS42L43_DECL_MUX(dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT); +CS42L43_DECL_MUX(dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT); +CS42L43_DECL_MUX(dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT); +CS42L43_DECL_MUX(dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT); +CS42L43_DECL_MUX(dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT); +CS42L43_DECL_MUX(dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT); +CS42L43_DECL_MUX(dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT); + +CS42L43_DECL_MUX(asrcint1, CS42L43_ASRC_INT1_INPUT1); +CS42L43_DECL_MUX(asrcint2, CS42L43_ASRC_INT2_INPUT1); +CS42L43_DECL_MUX(asrcint3, CS42L43_ASRC_INT3_INPUT1); +CS42L43_DECL_MUX(asrcint4, CS42L43_ASRC_INT4_INPUT1); +CS42L43_DECL_MUX(asrcdec1, CS42L43_ASRC_DEC1_INPUT1); +CS42L43_DECL_MUX(asrcdec2, CS42L43_ASRC_DEC2_INPUT1); +CS42L43_DECL_MUX(asrcdec3, CS42L43_ASRC_DEC3_INPUT1); +CS42L43_DECL_MUX(asrcdec4, CS42L43_ASRC_DEC4_INPUT1); + +CS42L43_DECL_MUX(isrc1int1, CS42L43_ISRC1INT1_INPUT1); +CS42L43_DECL_MUX(isrc1int2, CS42L43_ISRC1INT2_INPUT1); +CS42L43_DECL_MUX(isrc1dec1, CS42L43_ISRC1DEC1_INPUT1); +CS42L43_DECL_MUX(isrc1dec2, CS42L43_ISRC1DEC2_INPUT1); +CS42L43_DECL_MUX(isrc2int1, CS42L43_ISRC2INT1_INPUT1); +CS42L43_DECL_MUX(isrc2int2, CS42L43_ISRC2INT2_INPUT1); +CS42L43_DECL_MUX(isrc2dec1, CS42L43_ISRC2DEC1_INPUT1); +CS42L43_DECL_MUX(isrc2dec2, CS42L43_ISRC2DEC2_INPUT1); + +CS42L43_DECL_MUX(spdif1, CS42L43_SPDIF1_INPUT1); +CS42L43_DECL_MUX(spdif2, CS42L43_SPDIF2_INPUT1); + +CS42L43_DECL_MIXER(eq1, CS42L43_EQ1MIX_INPUT1); +CS42L43_DECL_MIXER(eq2, CS42L43_EQ2MIX_INPUT1); + +CS42L43_DECL_MIXER(amp1, CS42L43_AMP1MIX_INPUT1); +CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1); + +CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1); +CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1); + +static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_get_volsw(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_put_volsw(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_get_enum_double(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_put_enum_double(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof(priv->eq_coeffs)); + + return 0; +} + +static int cs42l43_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + snd_soc_dapm_mutex_lock(dapm); + + memcpy(priv->eq_coeffs, ucontrol->value.integer.value, sizeof(priv->eq_coeffs)); + + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + +static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + mutex_lock(&priv->spk_vu_lock); + + regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, + CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, + CS42L43_AMP1_2_VU_MASK, 0); + + mutex_unlock(&priv->spk_vu_lock); +} + +static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val; + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for shutters: %d\n", ret); + return ret; + } + + /* + * SHUTTER_CONTROL is a mix of volatile and non-volatile bits, so must + * be cached for the non-volatiles, so drop it from the cache here so + * we force a read. + */ + ret = regcache_drop_region(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, + CS42L43_SHUTTER_CONTROL); + if (ret) { + dev_err(priv->dev, "Failed to drop shutter from cache: %d\n", ret); + goto error; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val); + if (ret) { + dev_err(priv->dev, "Failed to check shutter status: %d\n", ret); + goto error; + } + + ret = !(val & BIT(shift)); + + dev_dbg(priv->dev, "%s shutter is %s\n", + BIT(shift) == CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK ? "Mic" : "Speaker", + ret ? "open" : "closed"); + +error: + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; +} + +static int cs42l43_decim_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT); + if (ret < 0) + return ret; + else if (!ret) + ucontrol->value.integer.value[0] = ret; + else + ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol); + + return ret; +} + +static int cs42l43_spk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT); + if (ret < 0) + return ret; + else if (!ret) + ucontrol->value.integer.value[0] = ret; + else + ret = snd_soc_get_volsw(kcontrol, ucontrol); + + return ret; +} + +static int cs42l43_spk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret > 0) + cs42l43_spk_vu_sync(priv); + + return ret; +} + +static const struct snd_kcontrol_new cs42l43_controls[] = { + SOC_ENUM_EXT("Jack Override", cs42l43_jack_enum, + cs42l43_jack_get, cs42l43_jack_put), + + SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2, + CS42L43_ADC_PGA_GAIN_SHIFT, + 0xF, 5, cs42l43_adc_tlv), + + SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL, + CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0), + SOC_DOUBLE("PDM2 Invert Switch", CS42L43_DMIC_PDM_CTRL, + CS42L43_PDM2L_INV_SHIFT, CS42L43_PDM2R_INV_SHIFT, 1, 0), + SOC_ENUM("PDM1 Clock", cs42l43_pdm1_clk), + SOC_ENUM("PDM2 Clock", cs42l43_pdm2_clk), + + SOC_SINGLE("Decimator 1 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 2 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 3 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 4 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + + SOC_ENUM("Decimator 1 WNF Corner Frequency", cs42l43_dec1_wnf_corner), + SOC_ENUM("Decimator 2 WNF Corner Frequency", cs42l43_dec2_wnf_corner), + SOC_ENUM("Decimator 3 WNF Corner Frequency", cs42l43_dec3_wnf_corner), + SOC_ENUM("Decimator 4 WNF Corner Frequency", cs42l43_dec4_wnf_corner), + + SOC_SINGLE("Decimator 1 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 2 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 3 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 4 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + + SOC_ENUM("Decimator 1 HPF Corner Frequency", cs42l43_dec1_hpf_corner), + SOC_ENUM("Decimator 2 HPF Corner Frequency", cs42l43_dec2_hpf_corner), + SOC_ENUM("Decimator 3 HPF Corner Frequency", cs42l43_dec3_hpf_corner), + SOC_ENUM("Decimator 4 HPF Corner Frequency", cs42l43_dec4_hpf_corner), + + SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + + SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + + SOC_DOUBLE_R_EXT("Speaker Digital Switch", + CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2, + CS42L43_AMP_MUTE_SHIFT, 1, 1, + cs42l43_spk_get, cs42l43_spk_put), + + SOC_DOUBLE_R_EXT_TLV("Speaker Digital Volume", + CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2, + CS42L43_AMP_VOL_SHIFT, + 0xBF, 0, snd_soc_get_volsw, cs42l43_spk_put, + cs42l43_speaker_tlv), + + SOC_ENUM("Speaker Ramp Up", cs42l43_speaker_ramp_up), + SOC_ENUM("Speaker Ramp Down", cs42l43_speaker_ramp_down), + + CS42L43_MIXER_VOLUMES("Speaker L", CS42L43_AMP1MIX_INPUT1), + CS42L43_MIXER_VOLUMES("Speaker R", CS42L43_AMP2MIX_INPUT1), + + SOC_DOUBLE_SX_TLV("Headphone Digital Volume", CS42L43_HPPATHVOL, + CS42L43_AMP3_PATH_VOL_SHIFT, CS42L43_AMP4_PATH_VOL_SHIFT, + 0x11B, 229, cs42l43_headphone_tlv), + + SOC_DOUBLE("Headphone Invert Switch", CS42L43_DACCNFG1, + CS42L43_AMP3_INV_SHIFT, CS42L43_AMP4_INV_SHIFT, 1, 0), + + SOC_SINGLE("Headphone Zero Cross Switch", CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_ZC_SHIFT, 1, 0), + SOC_SINGLE("Headphone Ramp Switch", CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_SFT_SHIFT, 1, 0), + SOC_ENUM("Headphone Ramp Rate", cs42l43_headphone_ramp), + + CS42L43_MIXER_VOLUMES("Headphone L", CS42L43_AMP3MIX_INPUT1), + CS42L43_MIXER_VOLUMES("Headphone R", CS42L43_AMP4MIX_INPUT1), + + SOC_ENUM("Tone 1 Frequency", cs42l43_tone1_freq), + SOC_ENUM("Tone 2 Frequency", cs42l43_tone2_freq), + + SOC_DOUBLE_EXT("EQ Switch", + CS42L43_MUTE_EQ_IN0, CS42L43_MUTE_EQ_CH1_SHIFT, + CS42L43_MUTE_EQ_CH2_SHIFT, 1, 1, + cs42l43_dapm_get_volsw, cs42l43_dapm_put_volsw), + + SND_SOC_BYTES_E("EQ Coefficients", 0, CS42L43_N_EQ_COEFFS, + cs42l43_eq_get, cs42l43_eq_put), + + CS42L43_MIXER_VOLUMES("EQ1", CS42L43_EQ1MIX_INPUT1), + CS42L43_MIXER_VOLUMES("EQ2", CS42L43_EQ2MIX_INPUT1), +}; + +static int cs42l43_eq_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int val; + int i, ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0, + CS42L43_WRITE_MODE_MASK, CS42L43_WRITE_MODE_MASK); + + for (i = 0; i < CS42L43_N_EQ_COEFFS; i++) + regmap_write(cs42l43->regmap, CS42L43_COEFF_DATA_IN0, + priv->eq_coeffs[i]); + + regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0, + CS42L43_WRITE_MODE_MASK, 0); + + return 0; + case SND_SOC_DAPM_POST_PMU: + ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_INIT_DONE0, + val, (val & CS42L43_INITIALIZE_DONE_MASK), + 2000, 10000); + if (ret) + dev_err(priv->dev, "Failed to start EQs: %d\n", ret); + + regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, 0); + return ret; + default: + return 0; + } +} + +struct cs42l43_pll_config { + unsigned int freq; + + unsigned int div; + unsigned int mode; + unsigned int cal; +}; + +static const struct cs42l43_pll_config cs42l43_pll_configs[] = { + { 2400000, 0x50000000, 0x1, 0xA4 }, + { 3000000, 0x40000000, 0x1, 0x83 }, + { 3072000, 0x40000000, 0x3, 0x80 }, +}; + +static int cs42l43_set_pll(struct cs42l43_codec *priv, unsigned int src, + unsigned int freq) +{ + struct cs42l43 *cs42l43 = priv->core; + + lockdep_assert_held(&cs42l43->pll_lock); + + if (priv->refclk_src == src && priv->refclk_freq == freq) + return 0; + + if (regmap_test_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK)) { + dev_err(priv->dev, "PLL active, can't change configuration\n"); + return -EBUSY; + } + + switch (src) { + case CS42L43_SYSCLK_MCLK: + case CS42L43_SYSCLK_SDW: + dev_dbg(priv->dev, "Source PLL from %s at %uHz\n", + src ? "SoundWire" : "MCLK", freq); + + priv->refclk_src = src; + priv->refclk_freq = freq; + + return 0; + default: + dev_err(priv->dev, "Invalid PLL source: 0x%x\n", src); + return -EINVAL; + } +} + +static int cs42l43_enable_pll(struct cs42l43_codec *priv) +{ + static const struct reg_sequence enable_seq[] = { + { CS42L43_OSC_DIV_SEL, 0x0, }, + { CS42L43_MCLK_SRC_SEL, CS42L43_OSC_PLL_MCLK_SEL_MASK, 5, }, + }; + struct cs42l43 *cs42l43 = priv->core; + const struct cs42l43_pll_config *config = NULL; + unsigned int div = 0; + unsigned int freq = priv->refclk_freq; + unsigned long time_left; + + lockdep_assert_held(&cs42l43->pll_lock); + + if (priv->refclk_src == CS42L43_SYSCLK_SDW) { + if (!freq) + freq = cs42l43->sdw_freq; + else if (!cs42l43->sdw_freq) + cs42l43->sdw_freq = freq; + } + + dev_dbg(priv->dev, "Enabling PLL at %uHz\n", freq); + + while (freq > cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq) { + div++; + freq /= 2; + } + + if (div <= CS42L43_PLL_REFCLK_DIV_MASK) { + int i; + + for (i = 0; i < ARRAY_SIZE(cs42l43_pll_configs); i++) { + if (freq == cs42l43_pll_configs[i].freq) { + config = &cs42l43_pll_configs[i]; + break; + } + } + } + + if (!config) { + dev_err(priv->dev, "No suitable PLL config: 0x%x, %uHz\n", div, freq); + return -EINVAL; + } + + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_DIV_MASK | CS42L43_PLL_REFCLK_SRC_MASK, + div << CS42L43_PLL_REFCLK_DIV_SHIFT | + priv->refclk_src << CS42L43_PLL_REFCLK_SRC_SHIFT); + regmap_write(cs42l43->regmap, CS42L43_FDIV_FRAC, config->div); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_MODE_BYPASS_500_MASK | + CS42L43_PLL_MODE_BYPASS_1029_MASK, + config->mode << CS42L43_PLL_MODE_BYPASS_1029_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_CAL_RATIO, + CS42L43_PLL_CAL_RATIO_MASK, config->cal); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, CS42L43_PLL_REFCLK_EN_MASK); + + reinit_completion(&priv->pll_ready); + + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_EN_MASK, CS42L43_PLL_EN_MASK); + + time_left = wait_for_completion_timeout(&priv->pll_ready, + msecs_to_jiffies(CS42L43_PLL_TIMEOUT_MS)); + if (!time_left) { + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, 0); + + dev_err(priv->dev, "Timeout out waiting for PLL\n"); + return -ETIMEDOUT; + } + + if (priv->refclk_src == CS42L43_SYSCLK_SDW) + cs42l43->sdw_pll_active = true; + + dev_dbg(priv->dev, "PLL locked in %ums\n", 200 - jiffies_to_msecs(time_left)); + + /* + * Reads are not allowed over Soundwire without OSC_DIV2_EN or the PLL, + * but you can not change to PLL with OSC_DIV2_EN set. So ensure the whole + * change over happens under the regmap lock to prevent any reads. + */ + regmap_multi_reg_write(cs42l43->regmap, enable_seq, ARRAY_SIZE(enable_seq)); + + return 0; +} + +static int cs42l43_disable_pll(struct cs42l43_codec *priv) +{ + static const struct reg_sequence disable_seq[] = { + { CS42L43_MCLK_SRC_SEL, 0x0, 5, }, + { CS42L43_OSC_DIV_SEL, CS42L43_OSC_DIV2_EN_MASK, }, + }; + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Disabling PLL\n"); + + lockdep_assert_held(&cs42l43->pll_lock); + + regmap_multi_reg_write(cs42l43->regmap, disable_seq, ARRAY_SIZE(disable_seq)); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, 0); + + cs42l43->sdw_pll_active = false; + + return 0; +} + +static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + mutex_lock(&cs42l43->pll_lock); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (priv->refclk_src == CS42L43_SYSCLK_MCLK) { + ret = clk_prepare_enable(priv->mclk); + if (ret) { + dev_err(priv->dev, "Failed to enable MCLK: %d\n", ret); + break; + } + } + + ret = cs42l43_enable_pll(priv); + break; + case SND_SOC_DAPM_POST_PMD: + ret = cs42l43_disable_pll(priv); + + if (priv->refclk_src == CS42L43_SYSCLK_MCLK) + clk_disable_unprepare(priv->mclk); + break; + default: + break; + } + + mutex_unlock(&cs42l43->pll_lock); + + return ret; +} + +static int cs42l43_dapm_wait_completion(struct completion *pmu, struct completion *pmd, + int event, int timeout_ms) +{ + unsigned long time_left; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + reinit_completion(pmu); + return 0; + case SND_SOC_DAPM_PRE_PMD: + reinit_completion(pmd); + return 0; + case SND_SOC_DAPM_POST_PMU: + time_left = wait_for_completion_timeout(pmu, msecs_to_jiffies(timeout_ms)); + break; + case SND_SOC_DAPM_POST_PMD: + time_left = wait_for_completion_timeout(pmd, msecs_to_jiffies(timeout_ms)); + break; + default: + return 0; + } + + if (!time_left) + return -ETIMEDOUT; + else + return 0; +} + +static int cs42l43_spkr_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + return cs42l43_dapm_wait_completion(&priv->spkr_startup, + &priv->spkr_shutdown, event, + CS42L43_SPK_TIMEOUT_MS); +} + +static int cs42l43_spkl_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + return cs42l43_dapm_wait_completion(&priv->spkl_startup, + &priv->spkl_shutdown, event, + CS42L43_SPK_TIMEOUT_MS); +} + +static int cs42l43_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int mask = 1 << w->shift; + unsigned int val = 0; + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + val = mask; + fallthrough; + case SND_SOC_DAPM_PRE_PMD: + priv->hp_ena &= ~mask; + priv->hp_ena |= val; + + ret = cs42l43_dapm_wait_completion(&priv->hp_startup, + &priv->hp_shutdown, event, + CS42L43_HP_TIMEOUT_MS); + if (ret) + return ret; + + if (!priv->load_detect_running) + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + mask, val); + break; + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + if (priv->load_detect_running) + break; + + ret = cs42l43_dapm_wait_completion(&priv->hp_startup, + &priv->hp_shutdown, event, + CS42L43_HP_TIMEOUT_MS); + if (ret) + return ret; + break; + default: + break; + } + + return 0; +} + +static int cs42l43_mic_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int reg, ramp, mute; + unsigned int *val; + int ret; + + switch (w->shift) { + case CS42L43_ADC1_EN_SHIFT: + case CS42L43_PDM1_DIN_L_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2; + ramp = CS42L43_DECIM1_VD_RAMP_MASK; + mute = CS42L43_DECIM1_MUTE_MASK; + val = &priv->decim_cache[0]; + break; + case CS42L43_ADC2_EN_SHIFT: + case CS42L43_PDM1_DIN_R_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2; + ramp = CS42L43_DECIM2_VD_RAMP_MASK; + mute = CS42L43_DECIM2_MUTE_MASK; + val = &priv->decim_cache[1]; + break; + case CS42L43_PDM2_DIN_L_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4; + ramp = CS42L43_DECIM3_VD_RAMP_MASK; + mute = CS42L43_DECIM3_MUTE_MASK; + val = &priv->decim_cache[2]; + break; + case CS42L43_PDM2_DIN_R_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4; + ramp = CS42L43_DECIM4_VD_RAMP_MASK; + mute = CS42L43_DECIM4_MUTE_MASK; + val = &priv->decim_cache[3]; + break; + default: + dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = regmap_read(cs42l43->regmap, reg, val); + if (ret) { + dev_err(priv->dev, + "Failed to cache decimator settings: %d\n", + ret); + return ret; + } + + regmap_update_bits(cs42l43->regmap, reg, mute | ramp, mute); + break; + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(cs42l43->regmap, reg, mute | ramp, *val); + break; + default: + break; + } + + return 0; +} + +static int cs42l43_adc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int mask = 1 << w->shift; + unsigned int val = 0; + int ret; + + ret = cs42l43_mic_ev(w, kcontrol, event); + if (ret) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + val = mask; + fallthrough; + case SND_SOC_DAPM_PRE_PMD: + priv->adc_ena &= ~mask; + priv->adc_ena |= val; + + if (!priv->load_detect_running) + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + mask, val); + fallthrough; + default: + return 0; + } +} + +static const struct snd_soc_dapm_widget cs42l43_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, cs42l43_pll_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("ADC1_IN1_P"), + SND_SOC_DAPM_INPUT("ADC1_IN1_N"), + SND_SOC_DAPM_INPUT("ADC1_IN2_P"), + SND_SOC_DAPM_INPUT("ADC1_IN2_N"), + SND_SOC_DAPM_INPUT("ADC2_IN_P"), + SND_SOC_DAPM_INPUT("ADC2_IN_N"), + + SND_SOC_DAPM_INPUT("PDM1_DIN"), + SND_SOC_DAPM_INPUT("PDM2_DIN"), + + SND_SOC_DAPM_MUX("ADC1 Input", SND_SOC_NOPM, 0, 0, &cs42l43_adc1_input_ctl), + + SND_SOC_DAPM_PGA_E("ADC1", SND_SOC_NOPM, CS42L43_ADC1_EN_SHIFT, 0, NULL, 0, + cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("ADC2", SND_SOC_NOPM, CS42L43_ADC2_EN_SHIFT, 0, NULL, 0, + cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_PGA_E("PDM1L", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_L_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM1R", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_R_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM2L", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_L_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM2R", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_R_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0, + &cs42l43_dec_mode_ctl[0]), + SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0, + &cs42l43_dec_mode_ctl[1]), + + SND_SOC_DAPM_PGA("Decimator 1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 4", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("FSYNC", 0, CS42L43_ASP_CTRL, CS42L43_ASP_FSYNC_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("BCLK", 1, CS42L43_ASP_CTRL, CS42L43_ASP_BCLK_EN_SHIFT, + 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 1, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH2_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 2, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH3_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 3, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH4_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX5", NULL, 4, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH5_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX6", NULL, 5, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH6_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 1, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH2_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX3", NULL, 2, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH3_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX4", NULL, 3, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH4_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX5", NULL, 4, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH5_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX6", NULL, 5, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH6_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_OUT("DP1TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX3", NULL, 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX4", NULL, 3, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP2TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP3TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP3TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP4TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP5RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP5RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP6RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP6RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP7RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP7RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-amp", 0, 0), + + SND_SOC_DAPM_PGA_E("AMP1", CS42L43_BLOCK_EN10, CS42L43_AMP1_EN_SHIFT, 0, NULL, 0, + cs42l43_spkl_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AMP2", CS42L43_BLOCK_EN10, CS42L43_AMP2_EN_SHIFT, 0, NULL, 0, + cs42l43_spkr_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("AMP1_OUT_P"), + SND_SOC_DAPM_OUTPUT("AMP1_OUT_N"), + SND_SOC_DAPM_OUTPUT("AMP2_OUT_P"), + SND_SOC_DAPM_OUTPUT("AMP2_OUT_N"), + + SND_SOC_DAPM_PGA("SPDIF", CS42L43_BLOCK_EN11, CS42L43_SPDIF_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPDIF_TX"), + + SND_SOC_DAPM_PGA_E("HP", SND_SOC_NOPM, CS42L43_HP_EN_SHIFT, 0, NULL, 0, + cs42l43_hp_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("AMP3_OUT"), + SND_SOC_DAPM_OUTPUT("AMP4_OUT"), + + SND_SOC_DAPM_SIGGEN("Tone"), + SND_SOC_DAPM_SUPPLY("Tone Generator", CS42L43_BLOCK_EN9, CS42L43_TONE_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 1", CS42L43_TONE_CH1_CTRL, + CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 2", CS42L43_TONE_CH2_CTRL, + CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0), + + SND_SOC_DAPM_SUPPLY("ISRC1", CS42L43_BLOCK_EN5, CS42L43_ISRC1_BANK_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ISRC2", CS42L43_BLOCK_EN5, CS42L43_ISRC2_BANK_EN_SHIFT, + 0, NULL, 0), + + SND_SOC_DAPM_PGA("ISRC1INT2", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1INT1", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1DEC2", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1DEC1", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_PGA("ISRC2INT2", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2INT1", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2DEC2", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2DEC1", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ASRC_INT", CS42L43_BLOCK_EN4, + CS42L43_ASRC_INT_BANK_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASRC_DEC", CS42L43_BLOCK_EN4, + CS42L43_ASRC_DEC_BANK_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_PGA("ASRC_INT1", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT2", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT3", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT3_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT4", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT4_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC1", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC2", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC3", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC3_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC4", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC4_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("EQ Clock", CS42L43_BLOCK_EN7, CS42L43_EQ_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_PGA_E("EQ", CS42L43_START_EQZ0, CS42L43_START_FILTER_SHIFT, + 0, NULL, 0, cs42l43_eq_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("Mixer Core", CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT, + 0, NULL, 0), + CS42L43_DAPM_MUX("ASPTX1", asptx1), + CS42L43_DAPM_MUX("ASPTX2", asptx2), + CS42L43_DAPM_MUX("ASPTX3", asptx3), + CS42L43_DAPM_MUX("ASPTX4", asptx4), + CS42L43_DAPM_MUX("ASPTX5", asptx5), + CS42L43_DAPM_MUX("ASPTX6", asptx6), + + CS42L43_DAPM_MUX("DP1TX1", dp1tx1), + CS42L43_DAPM_MUX("DP1TX2", dp1tx2), + CS42L43_DAPM_MUX("DP1TX3", dp1tx3), + CS42L43_DAPM_MUX("DP1TX4", dp1tx4), + CS42L43_DAPM_MUX("DP2TX1", dp2tx1), + CS42L43_DAPM_MUX("DP2TX2", dp2tx2), + CS42L43_DAPM_MUX("DP3TX1", dp3tx1), + CS42L43_DAPM_MUX("DP3TX2", dp3tx2), + CS42L43_DAPM_MUX("DP4TX1", dp4tx1), + CS42L43_DAPM_MUX("DP4TX2", dp4tx2), + + CS42L43_DAPM_MUX("ASRC INT1", asrcint1), + CS42L43_DAPM_MUX("ASRC INT2", asrcint2), + CS42L43_DAPM_MUX("ASRC INT3", asrcint3), + CS42L43_DAPM_MUX("ASRC INT4", asrcint4), + CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1), + CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2), + CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3), + CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4), + + CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1), + CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2), + CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1), + CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2), + CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1), + CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2), + CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1), + CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2), + + CS42L43_DAPM_MUX("SPDIF1", spdif1), + CS42L43_DAPM_MUX("SPDIF2", spdif2), + + CS42L43_DAPM_MIXER("EQ1", eq1), + CS42L43_DAPM_MIXER("EQ2", eq2), + + CS42L43_DAPM_MIXER("Speaker L", amp1), + CS42L43_DAPM_MIXER("Speaker R", amp2), + + CS42L43_DAPM_MIXER("Headphone L", amp3), + CS42L43_DAPM_MIXER("Headphone R", amp4), +}; + +static const struct snd_soc_dapm_route cs42l43_routes[] = { + { "ADC1_IN1_P", NULL, "PLL" }, + { "ADC1_IN1_N", NULL, "PLL" }, + { "ADC1_IN2_P", NULL, "PLL" }, + { "ADC1_IN2_N", NULL, "PLL" }, + { "ADC2_IN_P", NULL, "PLL" }, + { "ADC2_IN_N", NULL, "PLL" }, + { "PDM1_DIN", NULL, "PLL" }, + { "PDM2_DIN", NULL, "PLL" }, + { "AMP1_OUT_P", NULL, "PLL" }, + { "AMP1_OUT_N", NULL, "PLL" }, + { "AMP2_OUT_P", NULL, "PLL" }, + { "AMP2_OUT_N", NULL, "PLL" }, + { "SPDIF_TX", NULL, "PLL" }, + { "HP", NULL, "PLL" }, + { "AMP3_OUT", NULL, "PLL" }, + { "AMP4_OUT", NULL, "PLL" }, + { "Tone 1", NULL, "PLL" }, + { "Tone 2", NULL, "PLL" }, + { "ASP Playback", NULL, "PLL" }, + { "ASP Capture", NULL, "PLL" }, + { "DP1 Capture", NULL, "PLL" }, + { "DP2 Capture", NULL, "PLL" }, + { "DP3 Capture", NULL, "PLL" }, + { "DP4 Capture", NULL, "PLL" }, + { "DP5 Playback", NULL, "PLL" }, + { "DP6 Playback", NULL, "PLL" }, + { "DP7 Playback", NULL, "PLL" }, + + { "ADC1 Input", "IN1", "ADC1_IN1_P" }, + { "ADC1 Input", "IN1", "ADC1_IN1_N" }, + { "ADC1 Input", "IN2", "ADC1_IN2_P" }, + { "ADC1 Input", "IN2", "ADC1_IN2_N" }, + + { "ADC1", NULL, "ADC1 Input" }, + { "ADC2", NULL, "ADC2_IN_P" }, + { "ADC2", NULL, "ADC2_IN_N" }, + + { "PDM1L", NULL, "PDM1_DIN" }, + { "PDM1R", NULL, "PDM1_DIN" }, + { "PDM2L", NULL, "PDM2_DIN" }, + { "PDM2R", NULL, "PDM2_DIN" }, + + { "Decimator 1 Mode", "PDM", "PDM1L" }, + { "Decimator 1 Mode", "ADC", "ADC1" }, + { "Decimator 2 Mode", "PDM", "PDM1R" }, + { "Decimator 2 Mode", "ADC", "ADC2" }, + + { "Decimator 1", NULL, "Decimator 1 Mode" }, + { "Decimator 2", NULL, "Decimator 2 Mode" }, + { "Decimator 3", NULL, "PDM2L" }, + { "Decimator 4", NULL, "PDM2R" }, + + { "ASP Capture", NULL, "ASPTX1" }, + { "ASP Capture", NULL, "ASPTX2" }, + { "ASP Capture", NULL, "ASPTX3" }, + { "ASP Capture", NULL, "ASPTX4" }, + { "ASP Capture", NULL, "ASPTX5" }, + { "ASP Capture", NULL, "ASPTX6" }, + { "ASPTX1", NULL, "BCLK" }, + { "ASPTX2", NULL, "BCLK" }, + { "ASPTX3", NULL, "BCLK" }, + { "ASPTX4", NULL, "BCLK" }, + { "ASPTX5", NULL, "BCLK" }, + { "ASPTX6", NULL, "BCLK" }, + + { "ASPRX1", NULL, "ASP Playback" }, + { "ASPRX2", NULL, "ASP Playback" }, + { "ASPRX3", NULL, "ASP Playback" }, + { "ASPRX4", NULL, "ASP Playback" }, + { "ASPRX5", NULL, "ASP Playback" }, + { "ASPRX6", NULL, "ASP Playback" }, + { "ASPRX1", NULL, "BCLK" }, + { "ASPRX2", NULL, "BCLK" }, + { "ASPRX3", NULL, "BCLK" }, + { "ASPRX4", NULL, "BCLK" }, + { "ASPRX5", NULL, "BCLK" }, + { "ASPRX6", NULL, "BCLK" }, + + { "DP1 Capture", NULL, "DP1TX1" }, + { "DP1 Capture", NULL, "DP1TX2" }, + { "DP1 Capture", NULL, "DP1TX3" }, + { "DP1 Capture", NULL, "DP1TX4" }, + + { "DP2 Capture", NULL, "DP2TX1" }, + { "DP2 Capture", NULL, "DP2TX2" }, + + { "DP3 Capture", NULL, "DP3TX1" }, + { "DP3 Capture", NULL, "DP3TX2" }, + + { "DP4 Capture", NULL, "DP4TX1" }, + { "DP4 Capture", NULL, "DP4TX2" }, + + { "DP5RX1", NULL, "DP5 Playback" }, + { "DP5RX2", NULL, "DP5 Playback" }, + + { "DP6RX1", NULL, "DP6 Playback" }, + { "DP6RX2", NULL, "DP6 Playback" }, + + { "DP7RX1", NULL, "DP7 Playback" }, + { "DP7RX2", NULL, "DP7 Playback" }, + + { "AMP1", NULL, "vdd-amp" }, + { "AMP2", NULL, "vdd-amp" }, + + { "AMP1_OUT_P", NULL, "AMP1" }, + { "AMP1_OUT_N", NULL, "AMP1" }, + { "AMP2_OUT_P", NULL, "AMP2" }, + { "AMP2_OUT_N", NULL, "AMP2" }, + + { "SPDIF_TX", NULL, "SPDIF" }, + + { "AMP3_OUT", NULL, "HP" }, + { "AMP4_OUT", NULL, "HP" }, + + { "Tone 1", NULL, "Tone" }, + { "Tone 1", NULL, "Tone Generator" }, + { "Tone 2", NULL, "Tone" }, + { "Tone 2", NULL, "Tone Generator" }, + + { "ISRC1INT2", NULL, "ISRC1" }, + { "ISRC1INT1", NULL, "ISRC1" }, + { "ISRC1DEC2", NULL, "ISRC1" }, + { "ISRC1DEC1", NULL, "ISRC1" }, + + { "ISRC2INT2", NULL, "ISRC2" }, + { "ISRC2INT1", NULL, "ISRC2" }, + { "ISRC2DEC2", NULL, "ISRC2" }, + { "ISRC2DEC1", NULL, "ISRC2" }, + + { "ASRC_INT1", NULL, "ASRC_INT" }, + { "ASRC_INT2", NULL, "ASRC_INT" }, + { "ASRC_INT3", NULL, "ASRC_INT" }, + { "ASRC_INT4", NULL, "ASRC_INT" }, + { "ASRC_DEC1", NULL, "ASRC_DEC" }, + { "ASRC_DEC2", NULL, "ASRC_DEC" }, + { "ASRC_DEC3", NULL, "ASRC_DEC" }, + { "ASRC_DEC4", NULL, "ASRC_DEC" }, + + { "EQ", NULL, "EQ Clock" }, + + CS42L43_MUX_ROUTES("ASPTX1", "ASPTX1"), + CS42L43_MUX_ROUTES("ASPTX2", "ASPTX2"), + CS42L43_MUX_ROUTES("ASPTX3", "ASPTX3"), + CS42L43_MUX_ROUTES("ASPTX4", "ASPTX4"), + CS42L43_MUX_ROUTES("ASPTX5", "ASPTX5"), + CS42L43_MUX_ROUTES("ASPTX6", "ASPTX6"), + + CS42L43_MUX_ROUTES("DP1TX1", "DP1TX1"), + CS42L43_MUX_ROUTES("DP1TX2", "DP1TX2"), + CS42L43_MUX_ROUTES("DP1TX3", "DP1TX3"), + CS42L43_MUX_ROUTES("DP1TX4", "DP1TX4"), + CS42L43_MUX_ROUTES("DP2TX1", "DP2TX1"), + CS42L43_MUX_ROUTES("DP2TX2", "DP2TX2"), + CS42L43_MUX_ROUTES("DP3TX1", "DP3TX1"), + CS42L43_MUX_ROUTES("DP3TX2", "DP3TX2"), + CS42L43_MUX_ROUTES("DP4TX1", "DP4TX1"), + CS42L43_MUX_ROUTES("DP4TX2", "DP4TX2"), + + CS42L43_MUX_ROUTES("ASRC INT1", "ASRC_INT1"), + CS42L43_MUX_ROUTES("ASRC INT2", "ASRC_INT2"), + CS42L43_MUX_ROUTES("ASRC INT3", "ASRC_INT3"), + CS42L43_MUX_ROUTES("ASRC INT4", "ASRC_INT4"), + CS42L43_MUX_ROUTES("ASRC DEC1", "ASRC_DEC1"), + CS42L43_MUX_ROUTES("ASRC DEC2", "ASRC_DEC2"), + CS42L43_MUX_ROUTES("ASRC DEC3", "ASRC_DEC3"), + CS42L43_MUX_ROUTES("ASRC DEC4", "ASRC_DEC4"), + + CS42L43_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + CS42L43_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + CS42L43_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + CS42L43_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + CS42L43_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + CS42L43_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + CS42L43_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + CS42L43_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + + CS42L43_MUX_ROUTES("SPDIF1", "SPDIF"), + CS42L43_MUX_ROUTES("SPDIF2", "SPDIF"), + + CS42L43_MIXER_ROUTES("EQ1", "EQ"), + CS42L43_MIXER_ROUTES("EQ2", "EQ"), + + CS42L43_MIXER_ROUTES("Speaker L", "AMP1"), + CS42L43_MIXER_ROUTES("Speaker R", "AMP2"), + + CS42L43_MIXER_ROUTES("Headphone L", "HP"), + CS42L43_MIXER_ROUTES("Headphone R", "HP"), +}; + +static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id, + int src, unsigned int freq, int dir) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + mutex_lock(&cs42l43->pll_lock); + ret = cs42l43_set_pll(priv, src, freq); + mutex_unlock(&cs42l43->pll_lock); + + return ret; +} + +static int cs42l43_component_probe(struct snd_soc_component *component) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + + snd_soc_component_init_regmap(component, cs42l43->regmap); + + cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots); + cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots); + + priv->component = component; + priv->constraint = cs42l43_constraint; + + return 0; +} + +static const struct snd_soc_component_driver cs42l43_component_drv = { + .name = "cs42l43-codec", + + .probe = cs42l43_component_probe, + .set_sysclk = cs42l43_set_sysclk, + .set_jack = cs42l43_set_jack, + + .endianness = 1, + + .controls = cs42l43_controls, + .num_controls = ARRAY_SIZE(cs42l43_controls), + .dapm_widgets = cs42l43_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l43_widgets), + .dapm_routes = cs42l43_routes, + .num_dapm_routes = ARRAY_SIZE(cs42l43_routes), +}; + +struct cs42l43_irq { + unsigned int irq; + const char *name; + irq_handler_t handler; +}; + +static const struct cs42l43_irq cs42l43_irqs[] = { + { CS42L43_PLL_LOST_LOCK, "pll lost lock", cs42l43_pll_lost_lock }, + { CS42L43_PLL_READY, "pll ready", cs42l43_pll_ready }, + { CS42L43_HP_STARTUP_DONE, "hp startup", cs42l43_hp_startup }, + { CS42L43_HP_SHUTDOWN_DONE, "hp shutdown", cs42l43_hp_shutdown }, + { CS42L43_HSDET_DONE, "type detect", cs42l43_type_detect }, + { CS42L43_TIPSENSE_UNPLUG_PDET, "tip sense unplug", cs42l43_tip_sense }, + { CS42L43_TIPSENSE_PLUG_PDET, "tip sense plug", cs42l43_tip_sense }, + { CS42L43_DC_DETECT1_TRUE, "button press", cs42l43_button_press }, + { CS42L43_DC_DETECT1_FALSE, "button release", cs42l43_button_release }, + { CS42L43_HSBIAS_CLAMPED, "hsbias detect clamp", cs42l43_bias_detect_clamp }, + { CS42L43_AMP2_CLK_STOP_FAULT, "spkr clock stop", cs42l43_spkr_clock_stop }, + { CS42L43_AMP1_CLK_STOP_FAULT, "spkl clock stop", cs42l43_spkl_clock_stop }, + { CS42L43_AMP2_VDDSPK_FAULT, "spkr brown out", cs42l43_spkr_brown_out }, + { CS42L43_AMP1_VDDSPK_FAULT, "spkl brown out", cs42l43_spkl_brown_out }, + { CS42L43_AMP2_SHUTDOWN_DONE, "spkr shutdown", cs42l43_spkr_shutdown }, + { CS42L43_AMP1_SHUTDOWN_DONE, "spkl shutdown", cs42l43_spkl_shutdown }, + { CS42L43_AMP2_STARTUP_DONE, "spkr startup", cs42l43_spkr_startup }, + { CS42L43_AMP1_STARTUP_DONE, "spkl startup", cs42l43_spkl_startup }, + { CS42L43_AMP2_THERM_SHDN, "spkr thermal shutdown", cs42l43_spkr_therm_shutdown }, + { CS42L43_AMP1_THERM_SHDN, "spkl thermal shutdown", cs42l43_spkl_therm_shutdown }, + { CS42L43_AMP2_THERM_WARN, "spkr thermal warning", cs42l43_spkr_therm_warm }, + { CS42L43_AMP1_THERM_WARN, "spkl thermal warning", cs42l43_spkl_therm_warm }, + { CS42L43_AMP2_SCDET, "spkr short circuit", cs42l43_spkr_sc_detect }, + { CS42L43_AMP1_SCDET, "spkl short circuit", cs42l43_spkl_sc_detect }, + { CS42L43_HP_ILIMIT, "hp ilimit", cs42l43_hp_ilimit }, + { CS42L43_HP_LOADDET_DONE, "load detect done", cs42l43_load_detect }, +}; + +static int cs42l43_request_irq(struct cs42l43_codec *priv, + struct irq_domain *dom, const char * const name, + unsigned int irq, irq_handler_t handler) +{ + int ret; + + ret = irq_create_mapping(dom, irq); + if (ret < 0) + return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name); + + dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name); + + ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler, IRQF_ONESHOT, + name, priv); + if (ret) + return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name); + + return 0; +} + +static int cs42l43_shutter_irq(struct cs42l43_codec *priv, + struct irq_domain *dom, unsigned int shutter, + const char * const open_name, + const char * const close_name, + irq_handler_t handler) +{ + unsigned int open_irq, close_irq; + int ret; + + switch (shutter) { + case 0x1: + dev_warn(priv->dev, "Manual shutters, notifications not available\n"); + return 0; + case 0x2: + open_irq = CS42L43_GPIO1_RISE; + close_irq = CS42L43_GPIO1_FALL; + break; + case 0x4: + open_irq = CS42L43_GPIO2_RISE; + close_irq = CS42L43_GPIO2_FALL; + break; + case 0x8: + open_irq = CS42L43_GPIO3_RISE; + close_irq = CS42L43_GPIO3_FALL; + break; + default: + return 0; + } + + ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler); + if (ret) + return ret; + + return cs42l43_request_irq(priv, dom, open_name, open_irq, handler); +} + +static int cs42l43_codec_probe(struct platform_device *pdev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); + struct cs42l43_codec *priv; + struct irq_domain *dom; + unsigned int val; + int i, ret; + + dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY); + if (!dom) + return -EPROBE_DEFER; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->core = cs42l43; + + platform_set_drvdata(pdev, priv); + + mutex_init(&priv->jack_lock); + mutex_init(&priv->spk_vu_lock); + + init_completion(&priv->hp_startup); + init_completion(&priv->hp_shutdown); + init_completion(&priv->spkr_shutdown); + init_completion(&priv->spkl_shutdown); + init_completion(&priv->spkr_startup); + init_completion(&priv->spkl_startup); + init_completion(&priv->pll_ready); + init_completion(&priv->type_detect); + init_completion(&priv->load_detect); + + INIT_DELAYED_WORK(&priv->tip_sense_work, cs42l43_tip_sense_work); + INIT_DELAYED_WORK(&priv->bias_sense_timeout, cs42l43_bias_sense_timeout); + INIT_DELAYED_WORK(&priv->button_press_work, cs42l43_button_press_work); + INIT_WORK(&priv->button_release_work, cs42l43_button_release_work); + + pm_runtime_set_autosuspend_delay(priv->dev, 100); + pm_runtime_use_autosuspend(priv->dev); + pm_runtime_set_active(priv->dev); + pm_runtime_get_noresume(priv->dev); + devm_pm_runtime_enable(priv->dev); + + for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) { + ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name, + cs42l43_irqs[i].irq, cs42l43_irqs[i].handler); + if (ret) + goto err_pm; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val); + if (ret) { + dev_err(priv->dev, "Failed to check shutter source: %d\n", ret); + goto err_pm; + } + + ret = cs42l43_shutter_irq(priv, dom, val & CS42L43_MIC_SHUTTER_CFG_MASK, + "mic shutter open", "mic shutter close", + cs42l43_mic_shutter); + if (ret) + goto err_pm; + + ret = cs42l43_shutter_irq(priv, dom, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >> + CS42L43_SPK_SHUTTER_CFG_SHIFT, + "spk shutter open", "spk shutter close", + cs42l43_spk_shutter); + if (ret) + goto err_pm; + + // Don't use devm as we need to get against the MFD device + priv->mclk = clk_get_optional(cs42l43->dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err_probe(priv->dev, PTR_ERR(priv->mclk), "Failed to get mclk\n"); + goto err_pm; + } + + ret = devm_snd_soc_register_component(priv->dev, &cs42l43_component_drv, + cs42l43_dais, ARRAY_SIZE(cs42l43_dais)); + if (ret) { + dev_err_probe(priv->dev, ret, "Failed to register component\n"); + goto err_clk; + } + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return 0; + +err_clk: + clk_put(priv->mclk); +err_pm: + pm_runtime_put_sync(priv->dev); + + return ret; +} + +static int cs42l43_codec_remove(struct platform_device *pdev) +{ + struct cs42l43_codec *priv = platform_get_drvdata(pdev); + + clk_put(priv->mclk); + + return 0; +} + +static int __maybe_unused cs42l43_codec_runtime_resume(struct device *dev) +{ + struct cs42l43_codec *priv = dev_get_drvdata(dev); + + dev_dbg(priv->dev, "Runtime resume\n"); + + // Toggle the speaker volume update incase the speaker volume was synced + cs42l43_spk_vu_sync(priv); + + return 0; +} + +static const struct dev_pm_ops cs42l43_codec_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) +}; + +static const struct platform_device_id cs42l43_codec_id_table[] = { + { "cs42l43-codec", }, + {} +}; +MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table); + +static struct platform_driver cs42l43_codec_driver = { + .driver = { + .name = "cs42l43-codec", + .pm = &cs42l43_codec_pm_ops, + }, + + .probe = cs42l43_codec_probe, + .remove = cs42l43_codec_remove, + .id_table = cs42l43_codec_id_table, +}; +module_platform_driver(cs42l43_codec_driver); + +MODULE_IMPORT_NS(SND_SOC_CS42L43); + +MODULE_DESCRIPTION("CS42L43 CODEC Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h new file mode 100644 index 000000000000..bf4f728eea3e --- /dev/null +++ b/sound/soc/codecs/cs42l43.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS42L43 CODEC driver internal data + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CS42L43_ASOC_INT_H +#define CS42L43_ASOC_INT_H + +#define CS42L43_INTERNAL_SYSCLK 24576000 +#define CS42L43_DEFAULT_SLOTS 0x3F + +#define CS42L43_PLL_TIMEOUT_MS 200 +#define CS42L43_SPK_TIMEOUT_MS 100 +#define CS42L43_HP_TIMEOUT_MS 2000 +#define CS42L43_LOAD_TIMEOUT_MS 1000 + +#define CS42L43_ASP_MAX_CHANNELS 6 +#define CS42L43_N_EQ_COEFFS 15 + +#define CS42L43_N_BUTTONS 6 + +struct cs42l43_codec { + struct device *dev; + struct cs42l43 *core; + struct snd_soc_component *component; + + struct clk *mclk; + + int n_slots; + int slot_width; + int tx_slots[CS42L43_ASP_MAX_CHANNELS]; + int rx_slots[CS42L43_ASP_MAX_CHANNELS]; + struct snd_pcm_hw_constraint_list constraint; + + u32 eq_coeffs[CS42L43_N_EQ_COEFFS]; + + unsigned int refclk_src; + unsigned int refclk_freq; + struct completion pll_ready; + + unsigned int decim_cache[4]; + unsigned int adc_ena; + unsigned int hp_ena; + + struct completion hp_startup; + struct completion hp_shutdown; + struct completion spkr_shutdown; + struct completion spkl_shutdown; + struct completion spkr_startup; + struct completion spkl_startup; + // Lock to ensure speaker VU updates don't clash + struct mutex spk_vu_lock; + + // Lock for all jack detect operations + struct mutex jack_lock; + struct snd_soc_jack *jack_hp; + + bool use_ring_sense; + unsigned int tip_debounce_ms; + unsigned int bias_low; + unsigned int bias_sense_ua; + unsigned int bias_ramp_ms; + unsigned int detect_us; + unsigned int buttons[CS42L43_N_BUTTONS]; + + struct delayed_work tip_sense_work; + struct delayed_work bias_sense_timeout; + struct delayed_work button_press_work; + struct work_struct button_release_work; + struct completion type_detect; + struct completion load_detect; + + bool load_detect_running; + bool button_detect_running; + bool jack_present; + int jack_override; +}; + +#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW) + +int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction); + +#else + +static inline int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EINVAL; +} + +#define cs42l43_sdw_remove_peripheral NULL +#define cs42l43_sdw_set_stream NULL + +#endif + +int cs42l43_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *d); +void cs42l43_bias_sense_timeout(struct work_struct *work); +void cs42l43_tip_sense_work(struct work_struct *work); +void cs42l43_button_press_work(struct work_struct *work); +void cs42l43_button_release_work(struct work_struct *work); +irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data); +irqreturn_t cs42l43_button_press(int irq, void *data); +irqreturn_t cs42l43_button_release(int irq, void *data); +irqreturn_t cs42l43_tip_sense(int irq, void *data); +int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + +extern const struct soc_enum cs42l43_jack_enum; + +#endif /* CS42L43_ASOC_INT_H */ -- cgit v1.2.3 From ef24388225f87f2604522fe86fafacc271ec4a29 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:26 +0300 Subject: ASoC: SOF: ipc4-topology: Modify pipeline params based on SRC output format Modify the pipeline_params based on the SRC output format and set the sink_rate in the IPC data. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 633f6040d712..8bc12f12888d 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1838,10 +1838,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; + struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - struct snd_interval *rate; - int ret; + int ret, output_format_index; ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, pipeline_params, available_fmt); @@ -1853,22 +1853,23 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { + output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, + available_fmt, out_ref_rate, + out_ref_channels, out_ref_valid_bits); + if (output_format_index < 0) { dev_err(sdev->dev, "Failed to initialize output format for %s", swidget->widget->name); + return output_format_index; } /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config); - /* update pipeline_params for sink widgets */ - rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); - rate->min = src->sink_rate; - rate->max = rate->min; + out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; + src->sink_rate = out_audio_fmt->sampling_frequency; - return 0; + /* update pipeline_params for sink widgets */ + return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt); } static int -- cgit v1.2.3 From 56ecc164040b3685f6cb36b4d513d73d0f88140b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:27 +0300 Subject: ASoC: SOF: ipc4-topology: Fix the output reference params for SRC For playback, the SRC sink rate must be configured based on the requested output format which is restricted to only handle DAI's that support a single audio format for now. For capture, the SRC module should convert the rate to match the rate requested by the PCM hw_params. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8bc12f12888d..39649fddf16a 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1839,19 +1839,39 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; - struct sof_ipc4_audio_format *in_fmt; + struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret, output_format_index; + int output_format_index, input_format_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, + pipeline_params, available_fmt); + if (input_format_index < 0) + return input_format_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + /* + * For playback, the SRC sink rate will be configured based on the requested output + * format, which is restricted to only deal with DAI's with a single format for now. + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) { + dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n", + available_fmt->num_output_formats, swidget->widget->name); + return -EINVAL; + } + + /* + * SRC does not perform format conversion, so the output channels and valid bit depth must + * be the same as that of the input. + */ + in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); + + /* + * For capture, the SRC module should convert the rate to match the rate requested by the + * PCM hw_params. Set the reference params based on the fe_params unconditionally as it + * will be ignored for playback anyway. + */ + out_ref_rate = params_rate(fe_params); output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, out_ref_rate, -- cgit v1.2.3 From 769e8f6cd7182c95d4bd37491e13300ff067c7a7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:28 +0300 Subject: ASoC: SOF: ipc4-topology: Fix pipeline params at the output of copier When we walk the list of connected widgets from the source to the sink to prepare all widgets, the pipeline_params must be modified to reflect the output audio format at each widget. But, the copier only modifies the sample format in the pipeline_params. So, fix it to also modify the rate and channels. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 39649fddf16a..310aadd97d28 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,25 +1349,6 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif -static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) -{ - switch (bit_depth) { - case 16: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - break; - case 24: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - break; - case 32: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); - break; - default: - return -EINVAL; - } - - return 0; -} - static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1381,8 +1362,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; - struct snd_mask *fmt; - int out_sample_valid_bits; u32 gtw_cfg_config_length; u32 dma_config_tlv_size = 0; void **ipc_config_data; @@ -1664,11 +1643,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* modify the input params for the next widget */ - fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); - out_sample_valid_bits = - SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); - snd_mask_none(fmt); - ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits); + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format); if (ret) return ret; -- cgit v1.2.3 From 70b0924b22efe2135222a2c7141a83dfe0c78779 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:29 +0300 Subject: ASoC: SOF: ipc4-topology: Modify the reference output valid_bits for copier If the copier has only output valid_bits across all its output formats, the reference for selecting the output format must be set that instead of the valid_bits from the selected input format. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Seppo Ingalsuo Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 58 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 310aadd97d28..eff43635a88f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,6 +1349,31 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif +static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev, + struct sof_ipc4_pin_format *pin_fmts, + u32 pin_fmts_size) +{ + struct sof_ipc4_audio_format *fmt; + u32 valid_bits; + int i; + + fmt = &pin_fmts[0].audio_fmt; + valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + /* check if all output formats in topology are the same */ + for (i = 1; i < pin_fmts_size; i++) { + u32 _valid_bits; + + fmt = &pin_fmts[i].audio_fmt; + _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + if (_valid_bits != valid_bits) + return false; + } + + return true; +} + static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1371,6 +1396,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; int output_fmt_index; + bool single_output_format; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1504,6 +1530,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return ret; /* set the reference params for output format selection */ + single_output_format = sof_ipc4_copier_is_single_format(sdev, + available_fmt->output_pin_fmts, + available_fmt->num_output_formats); switch (swidget->id) { case snd_soc_dapm_aif_in: case snd_soc_dapm_dai_out: @@ -1514,17 +1543,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + if (!single_output_format) + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); break; } case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_in: - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); - if (out_ref_valid_bits < 0) - return out_ref_valid_bits; - out_ref_rate = params_rate(fe_params); out_ref_channels = params_channels(fe_params); + if (!single_output_format) { + out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (out_ref_valid_bits < 0) + return out_ref_valid_bits; + } break; default: /* @@ -1534,6 +1567,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return -EINVAL; } + /* + * if the output format is the same across all available output formats, choose + * that as the reference. + */ + if (single_output_format) { + struct sof_ipc4_audio_format *out_fmt; + + out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt; + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + } + + dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n", + swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits); + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits); -- cgit v1.2.3 From d0dab6b76a9f05bd25d7ad957c3275a9dec42a06 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:20 +0530 Subject: ASoC: SOF: amd: Add sof support for vangogh platform Add pci driver and platform driver to enable SOF support on ACP5x architecture based Vangogh platform. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 12 ++- sound/soc/sof/amd/Makefile | 4 +- sound/soc/sof/amd/acp-dsp-offset.h | 8 +- sound/soc/sof/amd/acp.h | 9 ++- sound/soc/sof/amd/pci-vangogh.c | 105 +++++++++++++++++++++++++ sound/soc/sof/amd/vangogh.c | 156 +++++++++++++++++++++++++++++++++++++ 6 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 sound/soc/sof/amd/pci-vangogh.c create mode 100644 sound/soc/sof/amd/vangogh.c diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 7dbc8df5cfe6..f2faa08f0c0e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -2,7 +2,7 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. config SND_SOC_SOF_AMD_TOPLEVEL tristate "SOF support for AMD audio DSPs" @@ -34,6 +34,16 @@ config SND_SOC_SOF_AMD_RENOIR help Select this option for SOF support on AMD Renoir platform +config SND_SOC_SOF_AMD_VANGOGH + tristate "SOF support for VANGOGH" + depends on SND_SOC_SOF_PCI + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support + on AMD Vangogh platform. + Say Y if you want to enable SOF on Vangogh. + If unsure select "N". + config SND_SOC_SOF_AMD_REMBRANDT tristate "SOF support for REMBRANDT" depends on SND_SOC_SOF_PCI diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index ef9f7df4e379..f3b375e67a6f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -2,13 +2,15 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o +snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o +obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) +=snd-sof-amd-vangogh.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 920155dee819..19ef2b4c46d6 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey */ @@ -49,27 +49,33 @@ #define ACP_CONTROL 0x1004 #define ACP3X_I2S_PIN_CONFIG 0x1400 +#define ACP5X_I2S_PIN_CONFIG 0x1400 #define ACP6X_I2S_PIN_CONFIG 0x1440 /* Registers offsets from ACP_PGFSM block */ #define ACP3X_PGFSM_BASE 0x141C +#define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 +#define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 +#define ACP5X_EXT_INTR_STAT 0x1808 #define ACP6X_EXT_INTR_STAT 0x1A0C #define ACP3X_DSP_SW_INTR_BASE 0x1814 +#define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 #define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP_ERROR_STATUS 0x18C4 #define ACP3X_AXI2DAGB_SEM_0 0x1880 +#define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 /* Registers from ACP_SHA block */ diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 72fa0af971f0..73c3e1373d42 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey */ @@ -32,6 +32,7 @@ #define ACP_DSP_INTR_EN_MASK 0x00000001 #define ACP3X_SRAM_PTE_OFFSET 0x02050000 +#define ACP5X_SRAM_PTE_OFFSET 0x02050000 #define ACP6X_SRAM_PTE_OFFSET 0x03800000 #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 @@ -56,9 +57,11 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 #define ACP_RN_PCI_ID 0x01 +#define ACP_VANGOGH_PCI_ID 0x50 #define ACP_RMB_PCI_ID 0x6F #define HOST_BRIDGE_CZN 0x1630 +#define HOST_BRIDGE_VGH 0x1645 #define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 #define ACP_PSP_TIMEOUT_US 1000000 @@ -163,6 +166,7 @@ struct acp_dsp_stream { struct sof_amd_acp_desc { unsigned int rev; + const char *name; unsigned int host_bridge_id; u32 pgfsm_base; u32 ext_intr_stat; @@ -253,6 +257,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops; extern struct snd_sof_dsp_ops sof_renoir_ops; int sof_renoir_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_vangogh_ops; +int sof_vangogh_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_rembrandt_ops; int sof_rembrandt_ops_init(struct snd_sof_dev *sdev); @@ -282,4 +288,5 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata int acp_probes_register(struct snd_sof_dev *sdev); void acp_probes_unregister(struct snd_sof_dev *sdev); +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; #endif diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c new file mode 100644 index 000000000000..d8be42fbcb6d --- /dev/null +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Venkata Prasad Potturu + +/*. + * PCI interface for Vangogh ACP device + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP5X_FUTURE_REG_ACLK_0 0x1864 + +static const struct sof_amd_acp_desc vangogh_chip_info = { + .rev = 5, + .name = "vangogh", + .host_bridge_id = HOST_BRIDGE_VGH, + .pgfsm_base = ACP5X_PGFSM_BASE, + .ext_intr_stat = ACP5X_EXT_INTR_STAT, + .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE, + .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0, + .acp_clkmux_sel = ACP5X_CLKMUX_SEL, + .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0, +}; + +static const struct sof_dev_desc vangogh_desc = { + .machines = snd_soc_acpi_amd_vangogh_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &vangogh_chip_info, + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-vangogh.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_vangogh_ops, + .ops_init = sof_vangogh_ops_init, +}; + +static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + if (pci->revision != ACP_VANGOGH_PCI_ID) + return -ENODEV; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +}; + +static void acp_pci_vgh_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id vgh_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&vangogh_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, vgh_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_vgh_driver = { + .name = KBUILD_MODNAME, + .id_table = vgh_pci_ids, + .probe = acp_pci_vgh_probe, + .remove = acp_pci_vgh_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_amd_vgh_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c new file mode 100644 index 000000000000..f3f6bd790788 --- /dev/null +++ b/sound/soc/sof/amd/vangogh.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: Venkata Prasad Potturu + +/* + * Hardware interface for Audio DSP on Vangogh platform + */ + +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_HS_INSTANCE 0 +#define I2S_BT_INSTANCE 1 +#define I2S_SP_INSTANCE 2 +#define PDM_DMIC_INSTANCE 3 +#define I2S_HS_VIRTUAL_INSTANCE 4 + +static struct snd_soc_dai_driver vangogh_sof_dai[] = { + [I2S_HS_INSTANCE] = { + .id = I2S_HS_INSTANCE, + .name = "acp-sof-hs", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_HS_VIRTUAL_INSTANCE] = { + .id = I2S_HS_VIRTUAL_INSTANCE, + .name = "acp-sof-hs-virtual", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS-Virtual controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, +}; + +/* Vangogh ops */ +struct snd_sof_dsp_ops sof_vangogh_ops; +EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); + +int sof_vangogh_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_vangogh_ops.drv = vangogh_sof_dai; + sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + + return 0; +} + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("VANGOGH SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 6a69b724b2f82b1c44852b432010fbe25f0e2b75 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:21 +0530 Subject: ASoC: SOF: amd: Add support for signed fw image loading Add support for signed firmware code bin and data bin loading for amd platforms. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 1 + sound/soc/sof/amd/acp-loader.c | 39 ++++++++++++++++++++++++++++++++++++-- sound/soc/sof/amd/acp.c | 6 +++++- sound/soc/sof/amd/acp.h | 8 ++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 19ef2b4c46d6..a913f1cc4c80 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -87,6 +87,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_DMA_INCLUDE_HDR 0x1CCC #define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index a4bce5a3ae48..a63c00b53a5e 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey @@ -158,7 +158,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) int ret; adata = sdev->pdata->hw_pdata; - size_fw = adata->fw_bin_size; + + if (adata->signed_fw_image) + size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; + else + size_fw = adata->fw_bin_size; page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; adata->fw_bin_page_count = page_count; @@ -219,3 +223,34 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) return 0; } EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata = plat_data->hw_pdata; + int ret; + + ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); + return ret; + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); + } + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, + (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); + + ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); + return ret; + + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); + } + + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, + (void *)adata->fw_dbin->data, adata->fw_dbin->size); + return ret; +} +EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index c450931ae77e..0072a62aa4ef 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. // // Authors: Vijendar Mukunda // Ajit Kumar Pandey @@ -235,6 +235,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } + if (adata->signed_fw_image) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); @@ -527,6 +530,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; sdev->debug_box.size = BOX_SIZE_1024; + adata->signed_fw_image = false; acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 73c3e1373d42..842105330369 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -41,6 +41,7 @@ #define DSP_FW_RUN_ENABLE 0x01 #define ACP_SHA_RUN 0x01 #define ACP_SHA_RESET 0x02 +#define ACP_SHA_HEADER 0x01 #define ACP_DMA_CH_RST 0x01 #define ACP_DMA_CH_GRACEFUL_RST_EN 0x10 #define ACP_ATU_CACHE_INVALID 0x01 @@ -82,6 +83,8 @@ #define SRAM1_SIZE 0x13A000 #define PROBE_STATUS_BIT BIT(31) +#define ACP_FIRMWARE_SIGNATURE 0x100 + enum clock_source { ACP_CLOCK_96M = 0, ACP_CLOCK_48M, @@ -181,15 +184,19 @@ struct sof_amd_acp_desc { /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + const struct firmware *fw_dbin; /* DMIC device */ struct platform_device *dmic_dev; unsigned int fw_bin_size; unsigned int fw_data_bin_size; + const char *fw_code_bin; + const char *fw_data_bin; u32 fw_bin_page_count; dma_addr_t sha_dma_addr; u8 *bin_buf; dma_addr_t dma_addr; u8 *data_buf; + bool signed_fw_image; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; @@ -214,6 +221,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev); /* DSP Loader callbacks */ int acp_sof_dsp_run(struct snd_sof_dev *sdev); int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev); int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); /* Block IO callbacks */ -- cgit v1.2.3 From f7da88003c53cf0eedabe609324a047b1921dfcc Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:22 +0530 Subject: ASoC: SOF: amd: Enable signed firmware image loading for Vangogh platform Enable signed firmware loading for Vangogh platform using dmi quirks. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 31 +++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 3 +++ sound/soc/sof/amd/vangogh.c | 6 ++++++ 3 files changed, 40 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 0072a62aa4ef..b2e00a10a03e 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h" +#define SECURED_FIRMWARE 1 + +const struct dmi_system_id acp_sof_quirk_table[] = { + { + /* Valve Jupiter device */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + .driver_data = (void *)SECURED_FIRMWARE, + }, + {} +}; +EXPORT_SYMBOL_GPL(acp_sof_quirk_table); + static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) { pci_write_config_dword(dev, 0x60, smn_addr); @@ -468,8 +484,10 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata; const struct sof_amd_acp_desc *chip; + const struct dmi_system_id *dmi_id; unsigned int addr; int ret; @@ -531,6 +549,19 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->debug_box.size = BOX_SIZE_1024; adata->signed_fw_image = false; + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) { + adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->signed_fw_image = dmi_id->driver_data; + + dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, + adata->fw_data_bin); + } acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 842105330369..19cad4fcf99a 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -11,6 +11,8 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H +#include + #include "../sof-priv.h" #include "../sof-audio.h" @@ -297,4 +299,5 @@ int acp_probes_register(struct snd_sof_dev *sdev); void acp_probes_unregister(struct snd_sof_dev *sdev); extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; +extern const struct dmi_system_id acp_sof_quirk_table[]; #endif diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index f3f6bd790788..de15d21aa6d9 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -142,12 +142,18 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { + const struct dmi_system_id *dmi_id; + /* common defaults */ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); sof_vangogh_ops.drv = vangogh_sof_dai; sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) + sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; + return 0; } -- cgit v1.2.3 From 8e6657159131f90b746572f6a5bd622b3ccac82d Mon Sep 17 00:00:00 2001 From: Senhong Liu Date: Sat, 19 Aug 2023 06:33:45 -0700 Subject: ASoC: rt5640: fix typos I noticed typos and i fixed them. Signed-off-by: Senhong Liu Link: https://lore.kernel.org/r/20230819133345.39961-1-liusenhong2022@email.szu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8920726c38e8..15e1a62b9e57 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2570,7 +2570,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640_disable_jack_detect(component); return; } @@ -2625,7 +2625,7 @@ static void rt5640_enable_hda_jack_detect( NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640->irq = -ENXIO; return; } -- cgit v1.2.3 From 2cbd5304ea393f0ca3aeebec2f6554a32ac02ce3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 01:11:23 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308151142.hoM5o9LV-lkp@intel.com/ Fixes: 446b31e89493 ("ASoC: soc-dai.h: remove unused call back functions") Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ra3ubid.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 10636506b622..437bfccd04f8 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -329,6 +329,8 @@ static int pxa2xx_i2s_remove(struct snd_soc_dai *dai) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) static const struct snd_soc_dai_ops pxa_i2s_dai_ops = { + .probe = pxa2xx_i2s_probe, + .remove = pxa2xx_i2s_remove, .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, @@ -338,8 +340,6 @@ static const struct snd_soc_dai_ops pxa_i2s_dai_ops = { }; static struct snd_soc_dai_driver pxa_i2s_dai = { - .probe = pxa2xx_i2s_probe, - .remove = pxa2xx_i2s_remove, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 26ef47e5ba600ead306ee19e0bf56c1bf59213a3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 22 Aug 2023 09:54:19 +0300 Subject: ASoC: SOF: ipc4-topology: Add module parameter to ignore the CPC value Add a new module parameter ipc4_ignore_cpc which can be used to force the kernel to ignore the queried CPC value for all firmware modules and use 0 instead. The CPC lookup is still done to report missing configurations and the debug print is going to be different to be explicit that the CPC is ignored and what was the value we would have used. The CPC value is sent to the firmware with the MOD_INIT_INSTANCE message and it is used by the firmware as a parameter for clock scaling. The flag is intended to be used only when there is a need to validate the firmware behavior regarding to clock scaling since the 0 CPC value will force the DSP to run in full speed, disabling the scaling and provides additional counter point to rule out clock management related issues. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20230822065419.24374-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index eff43635a88f..f2a30cd31378 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -17,6 +17,19 @@ #include "ipc4-topology.h" #include "ops.h" +/* + * The ignore_cpc flag can be used to ignore the CPC value for all modules by + * using 0 instead. + * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE + * message and it is used for clock scaling. + * 0 as CPC value will instruct the firmware to use maximum frequency, thus + * deactivating the clock scaling. + */ +static bool ignore_cpc; +module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444); +MODULE_PARM_DESC(ipc4_ignore_cpc, + "Ignore CPC values. This option will disable clock scaling in firmware."); + #define SOF_IPC4_GAIN_PARAM_ID 0 #define SOF_IPC4_TPLG_ABI_SIZE 6 #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 @@ -970,9 +983,16 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * /* Update base_config->cpc from the module manifest */ sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); - dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", - swidget->widget->name, base_config->ibs, base_config->obs, - base_config->cpc); + if (ignore_cpc) { + dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n", + swidget->widget->name, base_config->ibs, base_config->obs, + base_config->cpc); + base_config->cpc = 0; + } else { + dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", + swidget->widget->name, base_config->ibs, base_config->obs, + base_config->cpc); + } } static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, -- cgit v1.2.3 From 220adc0fda6bbc274fff5825e2fd7d3dcd719e5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 01:10:59 +0000 Subject: ASoC: fsl: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308152047.psX1QNDh-lkp@intel.com/ Cc: Randy Dunlap Fixes: 446b31e89493 ("ASoC: soc-dai.h: remove unused call back functions") Signed-off-by: Kuninori Morimoto Reported-by: Randy Dunlap Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Link: https://lore.kernel.org/r/87a5ujubj0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_ac97.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 40a4a2667394..1671bcd4ee3d 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -222,6 +222,7 @@ static int psc_ac97_probe(struct snd_soc_dai *cpu_dai) * psc_ac97_dai_template: template CPU Digital Audio Interface */ static const struct snd_soc_dai_ops psc_ac97_analog_ops = { + .probe = psc_ac97_probe, .hw_params = psc_ac97_hw_analog_params, .trigger = psc_ac97_trigger, }; @@ -233,7 +234,6 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = { static struct snd_soc_dai_driver psc_ac97_dai[] = { { .name = "mpc5200-psc-ac97.0", - .probe = psc_ac97_probe, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, -- cgit v1.2.3 From aa836152420af94d014ddd677a5f95544abef4f6 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:33 +0530 Subject: ASoC: SOF: amd: remove unused sha dma interrupt code During initial development time for RN platform, when SHA dma gets completed, SHA DMA engine used to raise the ACP interrupt. In ACP interrupt handler, SHA DMA interrupt got handled. Currently SHA DMA compleition is verified by checking transfer count using read poll time out logic. Remove unused SHA dma interrupt handling code. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-1-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index b2e00a10a03e..630c2c5fe4c7 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -337,14 +337,7 @@ static irqreturn_t acp_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - unsigned int val, count = ACP_HW_SEM_RETRY_COUNT; - - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); - if (val & ACP_SHA_STAT) { - /* Clear SHA interrupt raised by PSP */ - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val); - return IRQ_HANDLED; - } + unsigned int count = ACP_HW_SEM_RETRY_COUNT; while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { /* Wait until acquired HW Semaphore lock or timeout */ -- cgit v1.2.3 From 0a1428141f638fc6fba863de40f0dc7ea91a1d47 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:34 +0530 Subject: ASoC: SOF: amd: enable ACP external global interrupt Previously ACP SOF firmware used to enable the ACP external global interrupt register. This will restrict to report ACP host interrupts only after firmware loading is successful. This register needs to be set from host driver to handle other ACP interrupts(SoundWire Interrupts) before loading the ACP firmware. Add field for external interrupt enable register in acp descriptor structure and enable the external interrupt enable register. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-2-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 3 +++ sound/soc/sof/amd/acp.h | 1 + 2 files changed, 4 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 630c2c5fe4c7..651b56388cb6 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -420,6 +420,9 @@ static int acp_reset(struct snd_sof_dev *sdev) dev_err(sdev->dev, "timeout in releasing reset\n"); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->ext_intr_enb) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01); + return ret; } diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 19cad4fcf99a..97bcada822ef 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -174,6 +174,7 @@ struct sof_amd_acp_desc { const char *name; unsigned int host_bridge_id; u32 pgfsm_base; + u32 ext_intr_enb; u32 ext_intr_stat; u32 dsp_intr_base; u32 sram_pte_offset; -- cgit v1.2.3 From 60eb816ed850b33f5410b1223c5d4d935a6ceb79 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:35 +0530 Subject: ASoC: SOF: amd: add module parameter for firmware debug Add module parameter for firmware debug. If firmware debug flag is enabled, clear the fusion stall bit which is required for enabling firmware debugging through JTAG. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-3-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 3 ++- sound/soc/sof/amd/acp.c | 5 +++++ sound/soc/sof/amd/acp.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index a63c00b53a5e..a427673cfb03 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -207,6 +207,7 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); int acp_sof_dsp_run(struct snd_sof_dev *sdev) { + struct acp_dev_data *adata = sdev->pdata->hw_pdata; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int val; @@ -215,7 +216,7 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val); /* Some platforms won't support fusion DSP,keep offset zero for no support */ - if (desc->fusion_dsp_offset) { + if (desc->fusion_dsp_offset && adata->enable_fw_debug) { snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN); val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset); dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 651b56388cb6..ebc985e2aaad 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -22,6 +22,10 @@ #define SECURED_FIRMWARE 1 +static bool enable_fw_debug; +module_param(enable_fw_debug, bool, 0444); +MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); + const struct dmi_system_id acp_sof_quirk_table[] = { { /* Valve Jupiter device */ @@ -558,6 +562,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, adata->fw_data_bin); } + adata->enable_fw_debug = enable_fw_debug; acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 97bcada822ef..4dcceb764769 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -205,6 +205,7 @@ struct acp_dev_data { struct acp_dsp_stream *dtrace_stream; struct pci_dev *smn_dev; struct acp_dsp_stream *probe_stream; + bool enable_fw_debug; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); -- cgit v1.2.3 From f3b2f8b7158026e7a0ab67f5e36c195cdb4c1bf8 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:36 +0530 Subject: ASoC: SOF: amd: remove redundant clock mux selection register write ACP clock mux selection register is already programmed during acp init sequence. Remove the redundant register write. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-4-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index ebc985e2aaad..61faae74d637 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -464,7 +464,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_resume(struct snd_sof_dev *sdev) { - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int ret; ret = acp_init(sdev); @@ -472,12 +471,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) dev_err(sdev->dev, "ACP Init failed\n"); return ret; } - - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); - - ret = acp_memory_init(sdev); - - return ret; + return acp_memory_init(sdev); } EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); -- cgit v1.2.3 From 0d9e4cf5b66e0ffca3d8cf8e9a111d4793877afe Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:37 +0530 Subject: ASoC: SOF: amd: add conditional check for acp_clkmux_sel register Few AMD platforms require ACP ACLK as clock source. Add conditional check for clock mux selection register for switching between internal clock and ACP ACLK. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 61faae74d637..eceba9b794ab 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -423,7 +423,9 @@ static int acp_reset(struct snd_sof_dev *sdev) if (ret < 0) dev_err(sdev->dev, "timeout in releasing reset\n"); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->acp_clkmux_sel) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->ext_intr_enb) snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01); -- cgit v1.2.3 From 3d02e1c439b4140215b624d423aa3c7554b17a5a Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:38 +0530 Subject: ASoC: SOF: amd: clear panic mask status when panic occurs Due to scratch memory persistence, Once the DSP panic is reported, need to clear the panic mask after handling DSP panic. Otherwise, It results in DSP panic on next reboot. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-6-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-ipc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 81a2c096a185..fcb54f545fea 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -170,6 +170,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status), true); + status = 0; + acp_mailbox_write(sdev, sdev->dsp_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } snd_sof_ipc_msgs_rx(sdev); @@ -199,6 +201,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32)); if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true); + status = 0; + acp_mailbox_write(sdev, sdev->debug_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } -- cgit v1.2.3 From 38592ae6dc9f84b7a994c43de2136b8115ca30f6 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:39 +0530 Subject: ASoC: SOF: amd: clear dsp to host interrupt status DSP_SW_INTR_STAT_OFFSET is a common interrupt register which will be accessed by both ACP firmware and driver. This register contains register bits corresponds to host to dsp interrupts and vice versa. when dsp to host interrupt is reported, only clear dsp to host interrupt bit in DSP_SW_INTR_STAT_OFFSET. Fixes: 2e7c6652f9b8 ("ASoC: SOF: amd: Fix for handling spurious interrupts from DSP") Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-7-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index eceba9b794ab..19a801908b56 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -367,9 +367,9 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) unsigned int val; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); - if (val) { - val |= ACP_DSP_TO_HOST_IRQ; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val); + if (val & ACP_DSP_TO_HOST_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, + ACP_DSP_TO_HOST_IRQ); return IRQ_WAKE_THREAD; } -- cgit v1.2.3 From 6dd11b945951315ba4986844f20e83a0c27c1d38 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Aug 2023 22:55:44 +0200 Subject: ASoC: Delete UDA134x/L3 audio codec This codec was used by the deleted S3C board sound/soc/samsung/s3c24xx_uda134x.c. Fixes: 503278c12701 ("ASoC: samsung: remove unused drivers") Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230822-delete-l3-v2-1-b3ffc07348af@linaro.org Signed-off-by: Mark Brown --- include/sound/l3.h | 28 --- include/sound/uda134x.h | 24 -- sound/soc/codecs/Kconfig | 8 - sound/soc/codecs/Makefile | 4 - sound/soc/codecs/l3.c | 132 ---------- sound/soc/codecs/uda134x.c | 587 --------------------------------------------- sound/soc/codecs/uda134x.h | 33 --- 7 files changed, 816 deletions(-) delete mode 100644 include/sound/l3.h delete mode 100644 include/sound/uda134x.h delete mode 100644 sound/soc/codecs/l3.c delete mode 100644 sound/soc/codecs/uda134x.c delete mode 100644 sound/soc/codecs/uda134x.h diff --git a/include/sound/l3.h b/include/sound/l3.h deleted file mode 100644 index b6f58072237a..000000000000 --- a/include/sound/l3.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _L3_H_ -#define _L3_H_ 1 - -struct l3_pins { - void (*setdat)(struct l3_pins *, int); - void (*setclk)(struct l3_pins *, int); - void (*setmode)(struct l3_pins *, int); - - int gpio_data; - int gpio_clk; - int gpio_mode; - int use_gpios; - - int data_hold; - int data_setup; - int clock_high; - int mode_hold; - int mode; - int mode_setup; -}; - -struct device; - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); -int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap); - -#endif diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h deleted file mode 100644 index db82516da162..000000000000 --- a/include/sound/uda134x.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * uda134x.h -- UDA134x ALSA SoC Codec driver - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - */ - -#ifndef _UDA134X_H -#define _UDA134X_H - -#include - -struct uda134x_platform_data { - struct l3_pins l3; - void (*power) (int); - int model; -#define UDA134X_UDA1340 1 -#define UDA134X_UDA1341 2 -#define UDA134X_UDA1344 3 -#define UDA134X_UDA1345 4 -}; - -#endif /* _UDA134X_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9ddebd135892..95b5bd883215 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -15,7 +15,6 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" depends on COMPILE_TEST imply SND_SOC_88PM860X - imply SND_SOC_L3 imply SND_SOC_AB8500_CODEC imply SND_SOC_AC97_CODEC imply SND_SOC_AD1836 @@ -270,7 +269,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TWL4030 imply SND_SOC_TWL6040 imply SND_SOC_UDA1334 - imply SND_SOC_UDA134X imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X @@ -1010,9 +1008,6 @@ config SND_SOC_JZ4770_CODEC This driver can also be built as a module. If so, the module will be called snd-soc-jz4770-codec. -config SND_SOC_L3 - tristate - config SND_SOC_DA7210 tristate depends on SND_SOC_I2C_AND_SPI @@ -1969,9 +1964,6 @@ config SND_SOC_UDA1334 and has basic features such as de-emphasis (at 44.1 kHz sampling rate) and mute. -config SND_SOC_UDA134X - tristate - config SND_SOC_UDA1380 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 95cbb42253e2..c8502a49b40a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -131,7 +131,6 @@ snd-soc-jz4740-codec-objs := jz4740.o snd-soc-jz4725b-codec-objs := jz4725b.o snd-soc-jz4760-codec-objs := jz4760.o snd-soc-jz4770-codec-objs := jz4770.o -snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-lochnagar-sc-objs := lochnagar-sc.o @@ -303,7 +302,6 @@ snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda1334-objs := uda1334.o -snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o @@ -518,7 +516,6 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o obj-$(CONFIG_SND_SOC_JZ4760_CODEC) += snd-soc-jz4760-codec.o obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o -obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o @@ -687,7 +684,6 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o -obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c deleted file mode 100644 index b84f6f1f6800..000000000000 --- a/sound/soc/codecs/l3.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * L3 code - * - * Copyright (C) 2008, Christian Pellegrin - * - * based on: - * - * L3 bus algorithm module. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - */ - -#include -#include -#include -#include -#include - -#include - -/* - * Send one byte of data to the chip. Data is latched into the chip on - * the rising edge of the clock. - */ -static void sendbyte(struct l3_pins *adap, unsigned int byte) -{ - int i; - - for (i = 0; i < 8; i++) { - adap->setclk(adap, 0); - udelay(adap->data_hold); - adap->setdat(adap, byte & 1); - udelay(adap->data_setup); - adap->setclk(adap, 1); - udelay(adap->clock_high); - byte >>= 1; - } -} - -/* - * Send a set of bytes to the chip. We need to pulse the MODE line - * between each byte, but never at the start nor at the end of the - * transfer. - */ -static void sendbytes(struct l3_pins *adap, const u8 *buf, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i) { - udelay(adap->mode_hold); - adap->setmode(adap, 0); - udelay(adap->mode); - } - adap->setmode(adap, 1); - udelay(adap->mode_setup); - sendbyte(adap, buf[i]); - } -} - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) -{ - adap->setclk(adap, 1); - adap->setdat(adap, 1); - adap->setmode(adap, 1); - udelay(adap->mode); - - adap->setmode(adap, 0); - udelay(adap->mode_setup); - sendbyte(adap, addr); - udelay(adap->mode_hold); - - sendbytes(adap, data, len); - - adap->setclk(adap, 1); - adap->setdat(adap, 1); - adap->setmode(adap, 0); - - return len; -} -EXPORT_SYMBOL_GPL(l3_write); - - -static void l3_set_clk(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_clk, val); -} - -static void l3_set_data(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_data, val); -} - -static void l3_set_mode(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_mode, val); -} - -int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap) -{ - int ret; - - if (!adap->use_gpios) - return -EINVAL; - - ret = devm_gpio_request_one(dev, adap->gpio_data, - GPIOF_OUT_INIT_LOW, "l3_data"); - if (ret < 0) - return ret; - adap->setdat = l3_set_data; - - ret = devm_gpio_request_one(dev, adap->gpio_clk, - GPIOF_OUT_INIT_LOW, "l3_clk"); - if (ret < 0) - return ret; - adap->setclk = l3_set_clk; - - ret = devm_gpio_request_one(dev, adap->gpio_mode, - GPIOF_OUT_INIT_LOW, "l3_mode"); - if (ret < 0) - return ret; - adap->setmode = l3_set_mode; - - return 0; -} -EXPORT_SYMBOL_GPL(l3_set_gpio_ops); - -MODULE_DESCRIPTION("L3 bit-banging driver"); -MODULE_AUTHOR("Christian Pellegrin "); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c deleted file mode 100644 index 1a62bec94005..000000000000 --- a/sound/soc/codecs/uda134x.c +++ /dev/null @@ -1,587 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * uda134x.c -- UDA134X ALSA SoC Codec driver - * - * Modifications by Christian Pellegrin - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "uda134x.h" - - -#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 -#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) - -struct uda134x_priv { - int sysclk; - int dai_fmt; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; - - struct regmap *regmap; - struct uda134x_platform_data *pd; -}; - -static const struct reg_default uda134x_reg_defaults[] = { - { UDA134X_EA000, 0x04 }, - { UDA134X_EA001, 0x04 }, - { UDA134X_EA010, 0x04 }, - { UDA134X_EA011, 0x00 }, - { UDA134X_EA100, 0x00 }, - { UDA134X_EA101, 0x00 }, - { UDA134X_EA110, 0x00 }, - { UDA134X_EA111, 0x00 }, - { UDA134X_STATUS0, 0x00 }, - { UDA134X_STATUS1, 0x03 }, - { UDA134X_DATA000, 0x00 }, - { UDA134X_DATA001, 0x00 }, - { UDA134X_DATA010, 0x00 }, - { UDA134X_DATA011, 0x00 }, - { UDA134X_DATA1, 0x00 }, -}; - -/* - * Write to the uda134x registers - * - */ -static int uda134x_regmap_write(void *context, unsigned int reg, - unsigned int value) -{ - struct uda134x_platform_data *pd = context; - int ret; - u8 addr; - u8 data = value; - - switch (reg) { - case UDA134X_STATUS0: - case UDA134X_STATUS1: - addr = UDA134X_STATUS_ADDR; - data |= (reg - UDA134X_STATUS0) << 7; - break; - case UDA134X_DATA000: - case UDA134X_DATA001: - case UDA134X_DATA010: - case UDA134X_DATA011: - addr = UDA134X_DATA0_ADDR; - data |= (reg - UDA134X_DATA000) << 6; - break; - case UDA134X_DATA1: - addr = UDA134X_DATA1_ADDR; - break; - default: - /* It's an extended address register */ - addr = (reg | UDA134X_EXTADDR_PREFIX); - - ret = l3_write(&pd->l3, - UDA134X_DATA0_ADDR, &addr, 1); - if (ret != 1) - return -EIO; - - addr = UDA134X_DATA0_ADDR; - data = (value | UDA134X_EXTDATA_PREFIX); - break; - } - - ret = l3_write(&pd->l3, - addr, &data, 1); - if (ret != 1) - return -EIO; - - return 0; -} - -static inline void uda134x_reset(struct snd_soc_component *component) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - unsigned int mask = 1<<6; - - regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask); - msleep(1); - regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0); -} - -static int uda134x_mute(struct snd_soc_dai *dai, int mute, int direction) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component); - unsigned int mask = 1<<2; - unsigned int val; - - pr_debug("%s mute: %d\n", __func__, mute); - - if (mute) - val = mask; - else - val = 0; - - return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val); -} - -static int uda134x_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct snd_pcm_runtime *master_runtime; - - if (uda134x->master_substream) { - master_runtime = uda134x->master_substream->runtime; - - pr_debug("%s constraining to %d bits at %d\n", __func__, - master_runtime->sample_bits, - master_runtime->rate); - - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate); - - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits); - - uda134x->slave_substream = substream; - } else - uda134x->master_substream = substream; - - return 0; -} - -static void uda134x_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - if (uda134x->master_substream == substream) - uda134x->master_substream = uda134x->slave_substream; - - uda134x->slave_substream = NULL; -} - -static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - unsigned int hw_params = 0; - - if (substream == uda134x->slave_substream) { - pr_debug("%s ignoring hw_params for slave substream\n", - __func__); - return 0; - } - - pr_debug("%s sysclk: %d, rate:%d\n", __func__, - uda134x->sysclk, params_rate(params)); - - /* set SYSCLK / fs ratio */ - switch (uda134x->sysclk / params_rate(params)) { - case 512: - break; - case 384: - hw_params |= (1<<4); - break; - case 256: - hw_params |= (1<<5); - break; - default: - printk(KERN_ERR "%s unsupported fs\n", __func__); - return -EINVAL; - } - - pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, - uda134x->dai_fmt, params_format(params)); - - /* set DAI format and word length */ - switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_width(params)) { - case 16: - hw_params |= (1<<1); - break; - case 18: - hw_params |= (1<<2); - break; - case 20: - hw_params |= ((1<<2) | (1<<1)); - break; - default: - printk(KERN_ERR "%s unsupported format (right)\n", - __func__); - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_LEFT_J: - hw_params |= (1<<3); - break; - default: - printk(KERN_ERR "%s unsupported format\n", __func__); - return -EINVAL; - } - - return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, - STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params); -} - -static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_component *component = codec_dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__, - clk_id, freq, dir); - - /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable - because the codec is slave. Of course limitations of the clock - master (the IIS controller) apply. - We'll error out on set_hw_params if it's not OK */ - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { - uda134x->sysclk = freq; - return 0; - } - - printk(KERN_ERR "%s unsupported sysclk\n", __func__); - return -EINVAL; -} - -static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_component *component = codec_dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - pr_debug("%s fmt: %08X\n", __func__, fmt); - - /* codec supports only full consumer mode */ - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { - printk(KERN_ERR "%s unsupported clocking mode\n", __func__); - return -EINVAL; - } - - /* no support for clock inversion */ - if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { - printk(KERN_ERR "%s unsupported clock inversion\n", __func__); - return -EINVAL; - } - - /* We can't setup DAI format here as it depends on the word bit num */ - /* so let's just store the value for later */ - uda134x->dai_fmt = fmt; - - return 0; -} - -static int uda134x_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct uda134x_platform_data *pd = uda134x->pd; - pr_debug("%s bias level %d\n", __func__, level); - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - /* power on */ - if (pd->power) { - pd->power(1); - regcache_sync(uda134x->regmap); - } - break; - case SND_SOC_BIAS_STANDBY: - break; - case SND_SOC_BIAS_OFF: - /* power off */ - if (pd->power) { - pd->power(0); - regcache_mark_dirty(uda134x->regmap); - } - break; - } - return 0; -} - -static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", - "Minimum2", "Maximum"}; -static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const char *uda134x_mixmode[] = {"Differential", "Analog1", - "Analog2", "Both"}; - -static const struct soc_enum uda134x_mixer_enum[] = { -SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), -SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), -SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), -}; - -static const struct snd_kcontrol_new uda1341_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), -SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), -SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), -SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), - -SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), -SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), -SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), - -SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), -SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), -SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), - -SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), -SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), -SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), -SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), -SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1340_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1345_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -/* UDA1341 has the DAC/ADC power down in STATUS1 */ -static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0), -}; - -/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */ -static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0), -}; - -/* Common DAPM widgets */ -static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("VINL1"), - SND_SOC_DAPM_INPUT("VINR1"), - SND_SOC_DAPM_INPUT("VINL2"), - SND_SOC_DAPM_INPUT("VINR2"), - SND_SOC_DAPM_OUTPUT("VOUTL"), - SND_SOC_DAPM_OUTPUT("VOUTR"), -}; - -static const struct snd_soc_dapm_route uda134x_dapm_routes[] = { - { "ADC", NULL, "VINL1" }, - { "ADC", NULL, "VINR1" }, - { "ADC", NULL, "VINL2" }, - { "ADC", NULL, "VINR2" }, - { "VOUTL", NULL, "DAC" }, - { "VOUTR", NULL, "DAC" }, -}; - -static const struct snd_soc_dai_ops uda134x_dai_ops = { - .startup = uda134x_startup, - .shutdown = uda134x_shutdown, - .hw_params = uda134x_hw_params, - .mute_stream = uda134x_mute, - .set_sysclk = uda134x_set_dai_sysclk, - .set_fmt = uda134x_set_dai_fmt, - .no_capture_mute = 1, -}; - -static struct snd_soc_dai_driver uda134x_dai = { - .name = "uda134x-hifi", - /* playback capabilities */ - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* capture capabilities */ - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* pcm operations */ - .ops = &uda134x_dai_ops, -}; - -static int uda134x_soc_probe(struct snd_soc_component *component) -{ - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct uda134x_platform_data *pd = uda134x->pd; - const struct snd_soc_dapm_widget *widgets; - unsigned int num_widgets; - int ret; - - printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1341: - case UDA134X_UDA1344: - case UDA134X_UDA1345: - break; - default: - printk(KERN_ERR "UDA134X SoC codec: " - "unsupported model %d\n", - pd->model); - return -EINVAL; - } - - if (pd->power) - pd->power(1); - - uda134x_reset(component); - - if (pd->model == UDA134X_UDA1341) { - widgets = uda1341_dapm_widgets; - num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); - } else { - widgets = uda1340_dapm_widgets; - num_widgets = ARRAY_SIZE(uda1340_dapm_widgets); - } - - ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets); - if (ret) { - printk(KERN_ERR "%s failed to register dapm controls: %d", - __func__, ret); - return ret; - } - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1344: - ret = snd_soc_add_component_controls(component, uda1340_snd_controls, - ARRAY_SIZE(uda1340_snd_controls)); - break; - case UDA134X_UDA1341: - ret = snd_soc_add_component_controls(component, uda1341_snd_controls, - ARRAY_SIZE(uda1341_snd_controls)); - break; - case UDA134X_UDA1345: - ret = snd_soc_add_component_controls(component, uda1345_snd_controls, - ARRAY_SIZE(uda1345_snd_controls)); - break; - default: - printk(KERN_ERR "%s unknown codec type: %d", - __func__, pd->model); - return -EINVAL; - } - - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register controls\n"); - return ret; - } - - return 0; -} - -static const struct snd_soc_component_driver soc_component_dev_uda134x = { - .probe = uda134x_soc_probe, - .set_bias_level = uda134x_set_bias_level, - .dapm_widgets = uda134x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), - .dapm_routes = uda134x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), - .suspend_bias_off = 1, - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, -}; - -static const struct regmap_config uda134x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = UDA134X_DATA1, - .reg_defaults = uda134x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults), - .cache_type = REGCACHE_RBTREE, - - .reg_write = uda134x_regmap_write, -}; - -static int uda134x_codec_probe(struct platform_device *pdev) -{ - struct uda134x_platform_data *pd = pdev->dev.platform_data; - struct uda134x_priv *uda134x; - int ret; - - if (!pd) { - dev_err(&pdev->dev, "Missing L3 bitbang function\n"); - return -ENODEV; - } - - uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); - if (!uda134x) - return -ENOMEM; - - uda134x->pd = pd; - platform_set_drvdata(pdev, uda134x); - - if (pd->l3.use_gpios) { - ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3); - if (ret < 0) - return ret; - } - - uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, - &uda134x_regmap_config); - if (IS_ERR(uda134x->regmap)) - return PTR_ERR(uda134x->regmap); - - return devm_snd_soc_register_component(&pdev->dev, - &soc_component_dev_uda134x, &uda134x_dai, 1); -} - -static struct platform_driver uda134x_codec_driver = { - .driver = { - .name = "uda134x-codec", - }, - .probe = uda134x_codec_probe, -}; - -module_platform_driver(uda134x_codec_driver); - -MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h deleted file mode 100644 index 664618c2571c..000000000000 --- a/sound/soc/codecs/uda134x.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _UDA134X_CODEC_H -#define _UDA134X_CODEC_H - -#define UDA134X_L3ADDR 5 -#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) -#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) -#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) - -#define UDA134X_EXTADDR_PREFIX 0xC0 -#define UDA134X_EXTDATA_PREFIX 0xE0 - -/* UDA134X registers */ -#define UDA134X_EA000 0 -#define UDA134X_EA001 1 -#define UDA134X_EA010 2 -#define UDA134X_EA011 3 -#define UDA134X_EA100 4 -#define UDA134X_EA101 5 -#define UDA134X_EA110 6 -#define UDA134X_EA111 7 -#define UDA134X_STATUS0 8 -#define UDA134X_STATUS1 9 -#define UDA134X_DATA000 10 -#define UDA134X_DATA001 11 -#define UDA134X_DATA010 12 -#define UDA134X_DATA011 13 -#define UDA134X_DATA1 14 - -#define STATUS0_DAIFMT_MASK (~(7<<1)) -#define STATUS0_SYSCLK_MASK (~(3<<4)) - -#endif -- cgit v1.2.3 From 91e28d0b51f994c5968aee2a941e9f62bc9e15d7 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Wed, 23 Aug 2023 15:12:43 +0800 Subject: ASoC: dt-bindings: nau8821: Add single-ended input feature Add input with single-ended control. Signed-off-by: Seven Lee Link: https://lore.kernel.org/r/20230823071244.1861487-1-wtli@nuvoton.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml index fc2f4ce4db88..3e54abd4ca74 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -89,6 +89,12 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 default: 3072000 + nuvoton,left-input-single-end: + description: Enable left input with single-ended settings if set. + For the headset mic application, the single-ended control is + just limited to the left adc for design demand. + type: boolean + '#sound-dai-cells': const: 0 @@ -114,6 +120,7 @@ examples: nuvoton,jkdet-pull-enable; nuvoton,jkdet-pull-up; nuvoton,key-enable; + nuvoton,left-input-single-end; nuvoton,jkdet-polarity = ; nuvoton,micbias-voltage = <6>; nuvoton,vref-impedance = <2>; -- cgit v1.2.3 From 014ee0692f29da8b08fed5da0fa14e04698a50f7 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Wed, 23 Aug 2023 15:12:44 +0800 Subject: ASoC: nau8821: Improve AMIC recording performance. Since the hardware may be designed as a single-ended input, the headset mic record only supports single-ended input on the left side. This patch will enhance microphone recording performance for single-end. Signed-off-by: Seven Lee Link: https://lore.kernel.org/r/20230823071244.1861487-2-wtli@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8821.c | 42 +++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/nau8821.h | 25 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index ca6beb2d2649..f307374834b5 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -624,6 +624,36 @@ static int system_clock_control(struct snd_soc_dapm_widget *w, return 0; } +static int nau8821_left_fepga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + + if (!nau8821->left_input_single_end) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA, + NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, + NAU8821_ACDC_VREF_MICN | NAU8821_FEPGA_MODEL_AAF); + regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST, + NAU8821_HP_BOOST_DISCHRG_EN, NAU8821_HP_BOOST_DISCHRG_EN); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA, + NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, 0); + regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST, + NAU8821_HP_BOOST_DISCHRG_EN, 0); + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0, system_clock_control, SND_SOC_DAPM_POST_PMD), @@ -635,8 +665,10 @@ static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { NAU8821_POWERUP_ADCL_SFT, 0), SND_SOC_DAPM_ADC("ADCR Power", NULL, NAU8821_R72_ANALOG_ADC_2, NAU8821_POWERUP_ADCR_SFT, 0), + /* single-ended design only on the left */ SND_SOC_DAPM_PGA_S("Frontend PGA L", 1, NAU8821_R7F_POWER_UP_CONTROL, - NAU8821_PUP_PGA_L_SFT, 0, NULL, 0), + NAU8821_PUP_PGA_L_SFT, 0, nau8821_left_fepga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_S("Frontend PGA R", 1, NAU8821_R7F_POWER_UP_CONTROL, NAU8821_PUP_PGA_R_SFT, 0, NULL, 0), SND_SOC_DAPM_PGA_S("ADCL Digital path", 0, NAU8821_R01_ENA_CTRL, @@ -1677,6 +1709,8 @@ static int nau8821_read_device_properties(struct device *dev, "nuvoton,jkdet-pull-up"); nau8821->key_enable = device_property_read_bool(dev, "nuvoton,key-enable"); + nau8821->left_input_single_end = device_property_read_bool(dev, + "nuvoton,left-input-single-end"); ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity", &nau8821->jkdet_polarity); if (ret) @@ -1760,6 +1794,12 @@ static void nau8821_init_regs(struct nau8821 *nau8821) NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1, NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64); + if (nau8821->left_input_single_end) { + regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE, + NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN); + regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS, + NAU8821_MICBIAS_LOWNOISE_EN, NAU8821_MICBIAS_LOWNOISE_EN); + } } static int nau8821_setup_irq(struct nau8821 *nau8821) diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index d962293c218e..00a888ed07ce 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -433,6 +433,14 @@ #define NAU8821_DAC_CAPACITOR_MSB (0x1 << 1) #define NAU8821_DAC_CAPACITOR_LSB 0x1 +/* MUTE_MIC_L_N (0x6b) */ +#define NAU8821_MUTE_MICNL_SFT 5 +#define NAU8821_MUTE_MICNL_EN (0x1 << NAU8821_MUTE_MICNL_SFT) +#define NAU8821_MUTE_MICNR_SFT 4 +#define NAU8821_MUTE_MICNR_EN (0x1 << NAU8821_MUTE_MICNR_SFT) +#define NAU8821_MUTE_MICRP_SFT 2 +#define NAU8821_MUTE_MICRP_EN (0x1 << NAU8821_MUTE_MICRP_SFT) + /* ANALOG_ADC_1 (0x71) */ #define NAU8821_MICDET_EN_SFT 0 #define NAU8821_MICDET_MASK 0x1 @@ -463,23 +471,39 @@ /* MIC_BIAS (0x74) */ #define NAU8821_MICBIAS_JKR2 (0x1 << 12) +#define NAU8821_MICBIAS_LOWNOISE_SFT 10 +#define NAU8821_MICBIAS_LOWNOISE_EN (0x1 << NAU8821_MICBIAS_LOWNOISE_SFT) #define NAU8821_MICBIAS_POWERUP_SFT 8 +#define NAU8821_MICBIAS_POWERUP_EN (0x1 << NAU8821_MICBIAS_POWERUP_SFT) #define NAU8821_MICBIAS_VOLTAGE_SFT 0 #define NAU8821_MICBIAS_VOLTAGE_MASK 0x7 /* BOOST (0x76) */ #define NAU8821_PRECHARGE_DIS (0x1 << 13) #define NAU8821_GLOBAL_BIAS_EN (0x1 << 12) +#define NAU8821_HP_BOOST_DISCHRG_SFT 11 +#define NAU8821_HP_BOOST_DISCHRG_EN (0x1 << NAU8821_HP_BOOST_DISCHRG_SFT) #define NAU8821_HP_BOOST_DIS_SFT 9 #define NAU8821_HP_BOOST_DIS (0x1 << NAU8821_HP_BOOST_DIS_SFT) #define NAU8821_HP_BOOST_G_DIS (0x1 << 8) #define NAU8821_SHORT_SHUTDOWN_EN (0x1 << 6) /* FEPGA (0x77) */ +#define NAU8821_ACDC_CTRL_SFT 14 +#define NAU8821_ACDC_CTRL_MASK (0x3 << NAU8821_ACDC_CTRL_SFT) +#define NAU8821_ACDC_VREF_MICP (0x1 << NAU8821_ACDC_CTRL_SFT) +#define NAU8821_ACDC_VREF_MICN (0x2 << NAU8821_ACDC_CTRL_SFT) #define NAU8821_FEPGA_MODEL_SFT 4 #define NAU8821_FEPGA_MODEL_MASK (0xf << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_AAF (0x1 << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_DIS (0x2 << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_IMP12K (0x8 << NAU8821_FEPGA_MODEL_SFT) #define NAU8821_FEPGA_MODER_SFT 0 #define NAU8821_FEPGA_MODER_MASK 0xf +#define NAU8821_FEPGA_MODER_AAF 0x1 +#define NAU8821_FEPGA_MODER_DIS 0x2 +#define NAU8821_FEPGA_MODER_IMP12K 0x8 + /* PGA_GAIN (0x7e) */ #define NAU8821_PGA_GAIN_L_SFT 8 @@ -543,6 +567,7 @@ struct nau8821 { bool jkdet_enable; bool jkdet_pull_enable; bool jkdet_pull_up; + bool left_input_single_end; int jkdet_polarity; int jack_insert_debounce; int jack_eject_debounce; -- cgit v1.2.3 From bd4cee2fdf69b56c2bf3e7ec7c2e12b81e08005c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:31 +0000 Subject: ASoC: rsnd: enable clk_i approximate rate usage Basically Renesas sound ADG is assuming that it has accurately divisible input clock. But sometimes / some board might not have it. The clk_i from CPG is used for such case. It can't calculate accurate division, but can be used as approximate rate. This patch enable clk_i for such case. Signed-off-by: Kuninori Morimoto Acked-by: Adnan Ali Tested-by: Vincenzo De Michele Tested-by: Patrick Keil Link: https://lore.kernel.org/r/87msyizlfd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 0b8926600d90..c490d43aa18c 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -491,6 +491,7 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) unsigned long req_Hz[ADG_HZ_SIZE]; int clkout_size; int i, req_size; + int approximate = 0; const char *parent_clk_name = NULL; const char * const *clkout_name; int brg_table[] = { @@ -537,6 +538,26 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * rsnd_adg_ssi_clk_try_start() * rsnd_ssi_master_clk_start() */ + + /* + * [APPROXIMATE] + * + * clk_i (internal clock) can't create accurate rate, it will be approximate rate. + * + * + * + * clk_i needs x2 of required maximum rate. + * see + * - Minimum division of BRRA/BRRB + * - rsnd_ssi_clk_query() + * + * Sample Settings for TDM 8ch, 32bit width + * + * 8(ch) x 32(bit) x 44100(Hz) x 2 = 22579200 + * 8(ch) x 32(bit) x 48000(Hz) x 2 = 24576000 + * + * clock-frequency = <22579200 24576000>; + */ for_each_rsnd_clkin(clk, adg, i) { rate = clk_get_rate(clk); @@ -544,6 +565,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) continue; /* BRGA */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { div = 6; if (req_Hz[ADG_HZ_441]) @@ -555,10 +580,16 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 20; if (req_Hz[ADG_HZ_441]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } /* BRGB */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { div = 6; if (req_Hz[ADG_HZ_48]) @@ -570,10 +601,15 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 16; if (req_Hz[ADG_HZ_48]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } } + if (approximate) + dev_info(dev, "It uses CLK_I as approximate rate"); + clkout_name = clkout_name_gen2; clkout_size = ARRAY_SIZE(clkout_name_gen2); if (rsnd_is_gen4(priv)) -- cgit v1.2.3 From d059cd40aea6deae716bc6588f24e7b6b421f822 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:36 +0000 Subject: ASoC: rsnd: setup clock-out only when all conditions are right Current adg.c doesn't assume that requested clock out divide condition doesn't match. In such case, it will indicate strange message, and will register NULL clock, etc. It is just a DT setting miss, but is confusable. This patch check all conditions for it. Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lee2zlf7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index c490d43aa18c..919339b75a25 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -607,6 +607,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) } } + if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) && + !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441])) + goto rsnd_adg_get_clkout_end; + if (approximate) dev_info(dev, "It uses CLK_I as approximate rate"); -- cgit v1.2.3 From 80d4984f38631b1157dd51214ccd3d2fc6d56fbb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:48 +0000 Subject: ASoC: rsnd: tidyup brga/brgb default value default value for brga/brgb should be 0xff instead of 0x2. This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jztmzlew.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 919339b75a25..4acfb92e44f3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -502,8 +502,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) }; ckr = 0; - brga = 2; /* default 1/6 */ - brgb = 2; /* default 1/6 */ + brga = 0xff; /* default */ + brgb = 0xff; /* default */ /* * ADG supports BRRA/BRRB output only -- cgit v1.2.3 From ab0233747f9cf6ba6c6d0c60c1e0e2533db00302 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:54 +0000 Subject: ASoC: rsnd: remove default division of clock out Current adg has default division for BRRA/BRRB, but it was created at very beginning of the driver implementation, and is now an unnecessary settings. Because it has this default division, unexpected clockout might be selected. For example if it requests only 44.1kHz base clockout, unrequested 48kHz base clockout also will be selected. This patch remove default division of clock out Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il96zlep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 4acfb92e44f3..25d3316a50d1 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -485,7 +485,6 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) struct device_node *np = dev->of_node; struct property *prop; u32 ckr, brgx, brga, brgb; - u32 rate, div; u32 req_rate[ADG_HZ_SIZE] = {}; uint32_t count = 0; unsigned long req_Hz[ADG_HZ_SIZE]; @@ -559,6 +558,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * clock-frequency = <22579200 24576000>; */ for_each_rsnd_clkin(clk, adg, i) { + u32 rate, div; + rate = clk_get_rate(clk); if (0 == rate) /* not used */ @@ -569,10 +570,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; - if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { - div = 6; - if (req_Hz[ADG_HZ_441]) - div = rate / req_Hz[ADG_HZ_441]; + if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) { + div = rate / req_Hz[ADG_HZ_441]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brga = brgx; @@ -590,10 +589,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; - if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { - div = 6; - if (req_Hz[ADG_HZ_48]) - div = rate / req_Hz[ADG_HZ_48]; + if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) { + div = rate / req_Hz[ADG_HZ_48]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brgb = brgx; -- cgit v1.2.3 From 4acdf9aedd5624aae9335d70a9324d5aaec4034d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:51:02 +0000 Subject: ASoC: rsnd: setup BRGCKR/BRRA/BRRB on rsnd_adg_clk_control() Current adg.c will configure BRGCKR/BRRA/BRRB to output clock when it start sound. OTAH, rsnd_adg_clk_enable() will enables clk_a/b/c when driver was probed. But it is strange, these should be set in the same time. This patch fixup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6oqzlei.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 25d3316a50d1..230c48648af3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -358,8 +358,6 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ckr = 0x80000000; /* BRGB output = 48kHz */ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); - rsnd_mod_write(adg_mod, BRRA, adg->brga); - rsnd_mod_write(adg_mod, BRRB, adg->brgb); dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", (ckr) ? 'B' : 'A', @@ -372,9 +370,16 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; + if (enable) { + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); + rsnd_mod_write(adg_mod, BRRA, adg->brga); + rsnd_mod_write(adg_mod, BRRB, adg->brgb); + } + for_each_rsnd_clkin(clk, adg, i) { if (enable) { clk_prepare_enable(clk); -- cgit v1.2.3 From 206110c74c4af6772916acacae5f28993085bf18 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Mon, 21 Aug 2023 22:41:47 +0800 Subject: ASoC: dt-bindings: snps,designware-i2s: Add StarFive JH7110 SoC support Add the StarFive JH7110 (TX0/TX1/RX channel) SoC support in the bindings of Designware I2S controller. The I2S controller needs two reset items to work properly on the JH7110 SoC. And TX0 channel as master mode needs 5 clock items and TX1/RX channels as slave mode need 9 clock items on the JH7110 SoC. The RX channel needs System Register Controller property to enable it and other platforms do not need it. Signed-off-by: Xingyu Wu Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230821144151.207339-2-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown --- .../bindings/sound/snps,designware-i2s.yaml | 108 ++++++++++++++++++++- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml index a970fd264b21..a48d040b0a4f 100644 --- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml @@ -17,6 +17,9 @@ properties: - const: snps,designware-i2s - enum: - snps,designware-i2s + - starfive,jh7110-i2stx0 + - starfive,jh7110-i2stx1 + - starfive,jh7110-i2srx reg: maxItems: 1 @@ -29,15 +32,36 @@ properties: maxItems: 1 clocks: - description: Sampling rate reference clock - maxItems: 1 + items: + - description: Sampling rate reference clock + - description: APB clock + - description: Audio master clock + - description: Inner audio master clock source + - description: External audio master clock source + - description: Bit clock + - description: Left/right channel clock + - description: External bit clock + - description: External left/right channel clock + minItems: 1 clock-names: - const: i2sclk + items: + - const: i2sclk + - const: apb + - const: mclk + - const: mclk_inner + - const: mclk_ext + - const: bclk + - const: lrck + - const: bclk_ext + - const: lrck_ext + minItems: 1 resets: items: - description: Optional controller resets + - description: controller reset of Sampling rate + minItems: 1 dmas: items: @@ -51,6 +75,17 @@ properties: - const: rx minItems: 1 + starfive,syscon: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to System Register Controller sys_syscon node. + - description: I2S-rx enabled control offset of SYS_SYSCONSAIF__SYSCFG register. + - description: I2S-rx enabled control mask + description: + The phandle to System Register Controller syscon node and the I2S-rx(ADC) + enabled control offset and mask of SYS_SYSCONSAIF__SYSCFG register. + allOf: - $ref: dai-common.yaml# - if: @@ -66,6 +101,73 @@ allOf: properties: "#sound-dai-cells": const: 0 + - if: + properties: + compatible: + contains: + const: snps,designware-i2s + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + resets: + maxItems: 1 + else: + properties: + resets: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: starfive,jh7110-i2stx0 + then: + properties: + clocks: + minItems: 5 + maxItems: 5 + clock-names: + minItems: 5 + maxItems: 5 + required: + - resets + - if: + properties: + compatible: + contains: + const: starfive,jh7110-i2stx1 + then: + properties: + clocks: + minItems: 9 + maxItems: 9 + clock-names: + minItems: 9 + maxItems: 9 + required: + - resets + - if: + properties: + compatible: + contains: + const: starfive,jh7110-i2srx + then: + properties: + clocks: + minItems: 9 + maxItems: 9 + clock-names: + minItems: 9 + maxItems: 9 + required: + - resets + - starfive,syscon + else: + properties: + starfive,syscon: false required: - compatible -- cgit v1.2.3 From d6d6c513f5d2d14651336fb4e30f097822b46f29 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Mon, 21 Aug 2023 22:41:48 +0800 Subject: ASoC: dwc: Use ops to get platform data Use of_device_get_match_data() to get platform data. Signed-off-by: Xingyu Wu Link: https://lore.kernel.org/r/20230821144151.207339-3-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 0a4698008d64..e70d41d57dfd 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -691,7 +691,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, static int dw_i2s_probe(struct platform_device *pdev) { - const struct i2s_platform_data *pdata = pdev->dev.platform_data; + const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev); struct dw_i2s_dev *dev; struct resource *res; int ret, irq; -- cgit v1.2.3 From 52ea7c0543f8a39da8a6fc17a5ab36b7b58d5431 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Mon, 21 Aug 2023 22:41:49 +0800 Subject: ASoC: dwc: i2s: Add StarFive JH7110 SoC support Add StarFive JH7110(TX0/TX1/RX channels) SoC support in the designware I2S driver and a flag to check if it is on the JH7110 SoC. These channels need to enable clocks, resets and syscon register on the JH7110 SoC. So add init ops in platform data for the JH7110 SoC to do this. Their resets should be deassert before changing the parent of clocks so these are done in the init ops of platform data. The I2S controllers use DMA controller by platform data on the JH7110 and their settings about snd_dmaengine_dai_dma_data() should be added in the dw_configure_dai_by_pd(). And use dmaengine PCM registration if these do not have IRQ on the JH7110 SoC. Signed-off-by: Xingyu Wu Link: https://lore.kernel.org/r/20230821144151.207339-4-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown --- include/sound/designware_i2s.h | 3 + sound/soc/dwc/dwc-i2s.c | 304 ++++++++++++++++++++++++++++++++++++++--- sound/soc/dwc/local.h | 1 + 3 files changed, 287 insertions(+), 21 deletions(-) diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index 80d275b9ae0d..f6803205a9fb 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -21,6 +21,8 @@ struct i2s_clk_config_data { u32 sample_rate; }; +struct dw_i2s_dev; + struct i2s_platform_data { #define DWC_I2S_PLAY (1 << 0) #define DWC_I2S_RECORD (1 << 1) @@ -42,6 +44,7 @@ struct i2s_platform_data { void *capture_dma_data; bool (*filter)(struct dma_chan *chan, void *slave); int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); + int (*i2s_pd_init)(struct dw_i2s_dev *dev); }; struct i2s_dma_data { diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index e70d41d57dfd..5ab1b3eb2d28 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -198,7 +199,8 @@ static void i2s_start(struct dw_i2s_dev *dev, else i2s_write_reg(dev->i2s_base, IRER, 1); - if (dev->use_pio) + /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */ + if (dev->use_pio || dev->is_jh7110) i2s_enable_irqs(dev, substream->stream, config->chan_nr); else i2s_enable_dma(dev, substream->stream); @@ -216,7 +218,7 @@ static void i2s_stop(struct dw_i2s_dev *dev, else i2s_write_reg(dev->i2s_base, IRER, 0); - if (dev->use_pio) + if (dev->use_pio || dev->is_jh7110) i2s_disable_irqs(dev, substream->stream, 8); else i2s_disable_dma(dev, substream->stream); @@ -227,6 +229,21 @@ static void i2s_stop(struct dw_i2s_dev *dev, } } +static int dw_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + + if (dev->is_jh7110) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; + } + + return 0; +} + static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) { u32 ch_reg; @@ -453,6 +470,7 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops dw_i2s_dai_ops = { .probe = dw_i2s_dai_probe, + .startup = dw_i2s_startup, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, @@ -637,17 +655,39 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) idx = 1; - /* Set DMA slaves info */ - dev->play_dma_data.pd.data = pdata->play_dma_data; - dev->capture_dma_data.pd.data = pdata->capture_dma_data; - dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; - dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; - dev->play_dma_data.pd.max_burst = 16; - dev->capture_dma_data.pd.max_burst = 16; - dev->play_dma_data.pd.addr_width = bus_widths[idx]; - dev->capture_dma_data.pd.addr_width = bus_widths[idx]; - dev->play_dma_data.pd.filter = pdata->filter; - dev->capture_dma_data.pd.filter = pdata->filter; + + if (dev->is_jh7110) { + /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */ + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 idx2; + + if (COMP1_TX_ENABLED(comp1)) { + idx2 = COMP1_TX_WORDSIZE_0(comp1); + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.fifo_size = dev->fifo_th * 2 * + (fifo_width[idx2]) >> 8; + dev->play_dma_data.dt.maxburst = 16; + } + if (COMP1_RX_ENABLED(comp1)) { + idx2 = COMP2_RX_WORDSIZE_0(comp2); + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.fifo_size = dev->fifo_th * 2 * + (fifo_width[idx2] >> 8); + dev->capture_dma_data.dt.maxburst = 16; + } + } else { + /* Set DMA slaves info */ + dev->play_dma_data.pd.data = pdata->play_dma_data; + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; + dev->play_dma_data.pd.max_burst = 16; + dev->capture_dma_data.pd.max_burst = 16; + dev->play_dma_data.pd.addr_width = bus_widths[idx]; + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; + dev->play_dma_data.pd.filter = pdata->filter; + dev->capture_dma_data.pd.filter = pdata->filter; + } return 0; } @@ -689,6 +729,190 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } +/* clocks initialization with master mode on JH7110 SoC */ +static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev) +{ + static struct clk_bulk_data clks[] = { + { .id = "mclk" }, + { .id = "mclk_ext" }, + { .id = "mclk_inner" }, + { .id = "apb" }, + { .id = "i2sclk" }, + }; + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); + int ret; + struct clk *pclk; + struct clk *bclk_mst; + struct clk *mclk; + struct clk *mclk_ext; + struct clk *mclk_inner; + + if (IS_ERR(resets)) + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); + + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); + if (ret) + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); + + mclk = clks[0].clk; + mclk_ext = clks[1].clk; + mclk_inner = clks[2].clk; + pclk = clks[3].clk; + bclk_mst = clks[4].clk; + + ret = clk_prepare_enable(pclk); + if (ret) + goto exit; + + /* Use inner mclk first and avoid uninitialized gpio for external mclk */ + ret = clk_set_parent(mclk, mclk_inner); + if (ret) + goto err_dis_pclk; + + ret = clk_prepare_enable(bclk_mst); + if (ret) + goto err_dis_pclk; + + /* deassert resets before set clock parent */ + ret = reset_control_deassert(resets); + if (ret) + goto err_dis_all; + + /* external clock (12.288MHz) for Audio */ + ret = clk_set_parent(mclk, mclk_ext); + if (ret) + goto err_dis_all; + + /* i2sclk will be got and enabled repeatedly later and should be disabled now. */ + clk_disable_unprepare(bclk_mst); + clk_bulk_put(ARRAY_SIZE(clks), clks); + dev->is_jh7110 = true; + + return 0; + +err_dis_all: + clk_disable_unprepare(bclk_mst); +err_dis_pclk: + clk_disable_unprepare(pclk); +exit: + clk_bulk_put(ARRAY_SIZE(clks), clks); + return ret; +} + +/* clocks initialization with slave mode on JH7110 SoC */ +static int jh7110_i2s_crg_slave_init(struct dw_i2s_dev *dev) +{ + static struct clk_bulk_data clks[] = { + { .id = "mclk" }, + { .id = "mclk_ext" }, + { .id = "apb" }, + { .id = "bclk_ext" }, + { .id = "lrck_ext" }, + { .id = "bclk" }, + { .id = "lrck" }, + { .id = "mclk_inner" }, + { .id = "i2sclk" }, + }; + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); + int ret; + struct clk *pclk; + struct clk *bclk_mst; + struct clk *bclk_ext; + struct clk *lrck_ext; + struct clk *bclk; + struct clk *lrck; + struct clk *mclk; + struct clk *mclk_ext; + struct clk *mclk_inner; + + if (IS_ERR(resets)) + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); + + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); + if (ret) + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); + + mclk = clks[0].clk; + mclk_ext = clks[1].clk; + pclk = clks[2].clk; + bclk_ext = clks[3].clk; + lrck_ext = clks[4].clk; + bclk = clks[5].clk; + lrck = clks[6].clk; + mclk_inner = clks[7].clk; + bclk_mst = clks[8].clk; + + ret = clk_prepare_enable(pclk); + if (ret) + goto exit; + + ret = clk_set_parent(mclk, mclk_inner); + if (ret) + goto err_dis_pclk; + + ret = clk_prepare_enable(bclk_mst); + if (ret) + goto err_dis_pclk; + + ret = reset_control_deassert(resets); + if (ret) + goto err_dis_all; + + /* The sources of BCLK and LRCK are the external codec. */ + ret = clk_set_parent(bclk, bclk_ext); + if (ret) + goto err_dis_all; + + ret = clk_set_parent(lrck, lrck_ext); + if (ret) + goto err_dis_all; + + ret = clk_set_parent(mclk, mclk_ext); + if (ret) + goto err_dis_all; + + /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */ + clk_disable_unprepare(bclk_mst); + clk_bulk_put(ARRAY_SIZE(clks), clks); + dev->is_jh7110 = true; + + return 0; + +err_dis_all: + clk_disable_unprepare(bclk_mst); +err_dis_pclk: + clk_disable_unprepare(pclk); +exit: + clk_bulk_put(ARRAY_SIZE(clks), clks); + return ret; +} + +/* Special syscon initialization about RX channel with slave mode on JH7110 SoC */ +static int jh7110_i2srx_crg_init(struct dw_i2s_dev *dev) +{ + struct regmap *regmap; + unsigned int args[2]; + + regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node, + "starfive,syscon", + 2, args); + if (IS_ERR(regmap)) + return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n"); + + /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */ + regmap_update_bits(regmap, args[0], args[1], args[1]); + + return jh7110_i2s_crg_slave_init(dev); +} + +static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config) +{ + struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config); + u32 bclk_rate = config->sample_rate * 64; + + return clk_set_rate(dev->clk, bclk_rate); +} + static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev); @@ -712,15 +936,25 @@ static int dw_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); - dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); - if (IS_ERR(dev->reset)) - return PTR_ERR(dev->reset); + dev->dev = &pdev->dev; + dev->is_jh7110 = false; + if (pdata) { + if (pdata->i2s_pd_init) { + ret = pdata->i2s_pd_init(dev); + if (ret) + return ret; + } + } - ret = reset_control_deassert(dev->reset); - if (ret) - return ret; + if (!dev->is_jh7110) { + dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(dev->reset)) + return PTR_ERR(dev->reset); - dev->dev = &pdev->dev; + ret = reset_control_deassert(dev->reset); + if (ret) + return ret; + } irq = platform_get_irq_optional(pdev, 0); if (irq >= 0) { @@ -779,7 +1013,7 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } - if (!pdata) { + if (!pdata || dev->is_jh7110) { if (irq >= 0) { ret = dw_pcm_register(pdev); dev->use_pio = true; @@ -821,8 +1055,36 @@ static void dw_i2s_remove(struct platform_device *pdev) } #ifdef CONFIG_OF +static const struct i2s_platform_data jh7110_i2stx0_data = { + .cap = DWC_I2S_PLAY | DW_I2S_MASTER, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000, + .i2s_clk_cfg = jh7110_i2stx0_clk_cfg, + .i2s_pd_init = jh7110_i2s_crg_master_init, +}; + +static const struct i2s_platform_data jh7110_i2stx1_data = { + .cap = DWC_I2S_PLAY | DW_I2S_SLAVE, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_8000_192000, + .i2s_pd_init = jh7110_i2s_crg_slave_init, +}; + +static const struct i2s_platform_data jh7110_i2srx_data = { + .cap = DWC_I2S_RECORD | DW_I2S_SLAVE, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_8000_192000, + .i2s_pd_init = jh7110_i2srx_crg_init, +}; + static const struct of_device_id dw_i2s_of_match[] = { { .compatible = "snps,designware-i2s", }, + { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, }, + { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,}, + { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,}, {}, }; diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index 4ce96bac2f39..dce88c9ad5f3 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -123,6 +123,7 @@ struct dw_i2s_dev { u32 fifo_th; u32 l_reg; u32 r_reg; + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; -- cgit v1.2.3 From ea2cb26a98378b60be8e952eca801130c1da4c73 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 23 Aug 2023 00:19:42 +0000 Subject: ASoC: audio-graph-card2: add comment for format property We don't need to have "format" property on DT any more if CPU/Codec driver has .auto_selectable_formats settings on snd_soc_dai_ops. The sample dtsi doesn't have it. To avoid user confusion, this patch indicates it on comment. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edjuzk2p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2-custom-sample.dtsi | 7 +++++++ sound/soc/generic/audio-graph-card2.c | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 2ac0de3c21da..8acaa2ddb335 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -34,6 +34,13 @@ * ... * }; * + * + * Below sample doesn't use "format" property, + * because test-component driver (test-cpu/test-codec) is supporting + * snd_soc_dai_ops :: .auto_selectable_formats. + * see + * snd_soc_runtime_get_dai_fmt() + * linux/sound/soc/generic/test-component.c :: test_dai_formats */ / { /* diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 98732468a992..b1c675c6b6db 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -47,6 +47,18 @@ see graph_parse_daifmt(). + "format" property is no longer needed on DT if both CPU/Codec drivers are + supporting snd_soc_dai_ops :: .auto_selectable_formats. + see + snd_soc_runtime_get_dai_fmt() + + sample driver + linux/sound/soc/sh/rcar/core.c + linux/sound/soc/codecs/ak4613.c + linux/sound/soc/codecs/pcm3168a.c + linux/sound/soc/soc-utils.c + linux/sound/soc/generic/test-component.c + ************************************ Normal Audio-Graph ************************************ -- cgit v1.2.3 From a74048432fbb30e7a574747f6e1f47aef17010b0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 23 Aug 2023 09:32:50 -0700 Subject: ASoC: cs42l43: Initialize ret in default case in cs42l43_pll_ev() clang warns (or errors with CONFIG_WERROR=y): sound/soc/codecs/cs42l43.c:1371:2: error: variable 'ret' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] 1371 | default: | ^~~~~~~ sound/soc/codecs/cs42l43.c:1377:9: note: uninitialized use occurs here 1377 | return ret; | ^~~ sound/soc/codecs/cs42l43.c:1349:9: note: initialize the variable 'ret' to silence this warning 1349 | int ret; | ^ | = 0 1 error generated. Initialize ret to 0 in the default case, as there was nothing to do for other event types. Closes: https://github.com/ClangBuiltLinux/linux/issues/1922 Fixes: fc918cbe874e ("ASoC: cs42l43: Add support for the cs42l43") Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20230823-cs42l43_pll_ev-init-ret-v1-1-5836f1ad5dad@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 55a79219af35..18178ffa82f2 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -1369,6 +1369,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, clk_disable_unprepare(priv->mclk); break; default: + ret = 0; break; } -- cgit v1.2.3 From 2b59332ead54870ed0f1a8b122a1d640a4865fdc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 24 Aug 2023 11:39:02 +0100 Subject: ASoC: cs42l43: Use new-style PM runtime macros Update to the newer style PM runtime macros, no functional change. Signed-off-by: Charles Keepax Date: Thu, 24 Aug 2023 02:02:49 +0000 Subject: ASoC: audio-graph-card.c: move audio_graph_parse_of() Current audio-graph-card functions definition are like below (A)' static int graph_get_dais_count(); (B) int audio_graph_parse_of(...) { ... (A) ret = graph_get_dais_count(); ... } (A) static int graph_get_dais_count(...) { ... } (C) We don't need to have (A)' definition if audio_graph_parse_of() (B) was defined at (C). This patch moves (B) to (C). Signed-off-by: Kuninori Morimoto owner = THIS_MODULE; - card->dev = dev; - - ret = graph_get_dais_count(priv, li); - if (ret < 0) - return ret; - - if (!li->link) - return -EINVAL; - - ret = asoc_simple_init_priv(priv, li); - if (ret < 0) - return ret; - - priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); - if (IS_ERR(priv->pa_gpio)) { - ret = PTR_ERR(priv->pa_gpio); - dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - return ret; - } - - ret = asoc_simple_parse_widgets(card, NULL); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_routing(card, NULL); - if (ret < 0) - return ret; - - memset(li, 0, sizeof(*li)); - ret = graph_for_each_link(priv, li, - graph_dai_link_of, - graph_dai_link_of_dpcm); - if (ret < 0) - goto err; - - ret = asoc_simple_parse_card_name(card, NULL); - if (ret < 0) - goto err; - - snd_soc_card_set_drvdata(card, priv); - - asoc_simple_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - devm_kfree(dev, li); - return 0; - -err: - asoc_simple_clean_reference(card); - - return dev_err_probe(dev, ret, "parse error\n"); -} -EXPORT_SYMBOL_GPL(audio_graph_parse_of); - static int graph_count_noml(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -612,6 +541,74 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv, graph_count_dpcm); } +int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) +{ + struct snd_soc_card *card = simple_priv_to_card(priv); + struct link_info *li; + int ret; + + li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + if (!li) + return -ENOMEM; + + card->owner = THIS_MODULE; + card->dev = dev; + + ret = graph_get_dais_count(priv, li); + if (ret < 0) + return ret; + + if (!li->link) + return -EINVAL; + + ret = asoc_simple_init_priv(priv, li); + if (ret < 0) + return ret; + + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); + if (IS_ERR(priv->pa_gpio)) { + ret = PTR_ERR(priv->pa_gpio); + dev_err(dev, "failed to get amplifier gpio: %d\n", ret); + return ret; + } + + ret = asoc_simple_parse_widgets(card, NULL); + if (ret < 0) + return ret; + + ret = asoc_simple_parse_routing(card, NULL); + if (ret < 0) + return ret; + + memset(li, 0, sizeof(*li)); + ret = graph_for_each_link(priv, li, + graph_dai_link_of, + graph_dai_link_of_dpcm); + if (ret < 0) + goto err; + + ret = asoc_simple_parse_card_name(card, NULL); + if (ret < 0) + goto err; + + snd_soc_card_set_drvdata(card, priv); + + asoc_simple_debug_info(priv); + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) + goto err; + + devm_kfree(dev, li); + return 0; + +err: + asoc_simple_clean_reference(card); + + return dev_err_probe(dev, ret, "parse error\n"); +} +EXPORT_SYMBOL_GPL(audio_graph_parse_of); + static int graph_probe(struct platform_device *pdev) { struct asoc_simple_priv *priv; -- cgit v1.2.3 From 8886e1b03669c498f7a24bc5e483f46db5e81f82 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Thu, 24 Aug 2023 12:17:10 -0700 Subject: ASoC: codecs: Fix error code in aw88261_i2c_probe() Passing zero to dev_err_probe is a success which is incorrect when i2c_check_functionality() fails. Fix this by passing -ENXIO instead of zero to dev_err_probe(). Fixes: 028a2ae25691 ("ASoC: codecs: Add aw88261 amplifier driver") Reported-by: kernel test robot adapter, I2C_FUNC_I2C); if (!ret) - return dev_err_probe(&i2c->dev, ret, "check_functionality failed"); + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed"); aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL); if (!aw88261) -- cgit v1.2.3 From 199cd64140f222c66b68ebe288a3fcd0570e2e41 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 24 Aug 2023 22:38:37 +0300 Subject: ASoC: soc-core.c: Do not error if a DAI link component is not found A recent cleanup of soc_dai_link_sanity_check() is responsible for generating lots of confusing errors before returning -EPROBE_DEFER: acp5x_mach acp5x_mach.0: ASoC: Component acp5x_i2s_dma.0 not found for link acp5x-8821-play [...] acp5x_mach acp5x_mach.0: ASoC: Component spi-VLV1776:00 not found for link acp5x-CS35L41-Stereo [...] acp5x_mach acp5x_mach.0: ASoC: Component spi-VLV1776:01 not found for link acp5x-CS35L41-Stereo Switch back to the initial behaviour of logging those messages on KERN_DEBUG level instead of KERN_ERR. While at it, use the correct form of the verb in 'component_not_find' label. Fixes: 0e66a2c69409 ("ASoC: soc-core.c: cleanup soc_dai_link_sanity_check()") Signed-off-by: Cristian Ciocaltea dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name); return -EINVAL; -component_not_find: - dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name); +component_not_found: + dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name); return -EPROBE_DEFER; dai_empty: -- cgit v1.2.3