From e8bd54b0664bc275b72a4d332b0d08b720f418ec Mon Sep 17 00:00:00 2001 From: sunliming Date: Tue, 19 Jul 2022 09:56:22 +0800 Subject: [PATCH 001/228] drm/msm/dsi: fix the inconsistent indenting [ Upstream commit 2f25a1fb4ec516c5ad67afd754334b491b9f09a5 ] Fix the inconsistent indenting in function msm_dsi_dphy_timing_calc_v3(). Fix the following smatch warnings: drivers/gpu/drm/msm/dsi/phy/dsi_phy.c:350 msm_dsi_dphy_timing_calc_v3() warn: inconsistent indenting Fixes: f1fa7ff44056 ("drm/msm/dsi: implement auto PHY timing calculator for 10nm PHY") Reported-by: kernel test robot Signed-off-by: sunliming Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/494662/ Link: https://lore.kernel.org/r/20220719015622.646718-1-sunliming@kylinos.cn Signed-off-by: Abhinav Kumar Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index a878b8b079c64..6a917fe69a833 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -347,7 +347,7 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, } else { timing->shared_timings.clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false); - timing->shared_timings.clk_pre_inc_by_2 = 0; + timing->shared_timings.clk_pre_inc_by_2 = 0; } timing->ta_go = 3; From 0a4f633548c495f8598b546a0f3eba5e2f101dbe Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Thu, 11 Aug 2022 15:57:50 -0700 Subject: [PATCH 002/228] drm/msm/dp: delete DP_RECOVERED_CLOCK_OUT_EN to fix tps4 [ Upstream commit 032d57960176ac01cc5adff5bcc5eb51317f8781 ] Data Symbols scrambled is required for tps4 at link training 2. Therefore SCRAMBLING_DISABLE bit should not be set for tps4 to work. RECOVERED_CLOCK_OUT_EN is for enable simple EYE test for jitter measurement with minimal equipment for embedded applications purpose and is not required to be set during normal operation. Current implementation always have RECOVERED_CLOCK_OUT_EN bit set which cause SCRAMBLING_DISABLE bit wrongly set at tps4 which prevent tps4 from working. This patch delete setting RECOVERED_CLOCK_OUT_EN to fix SCRAMBLING_DISABLE be wrongly set at tps4. Changes in v2: -- fix Fixes tag Changes in v3: -- revise commit text Changes in v4: -- fix commit text newline Changes in v5: -- fix commit text line over 75 chars Fixes: c943b4948b58 ("drm/msm/dp: add displayPort driver support") Signed-off-by: Kuogee Hsieh Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/497194/ Link: https://lore.kernel.org/r/1660258670-4200-1-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Abhinav Kumar Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index b6f4ce2a48afe..6d9eec98e0d38 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1198,7 +1198,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, if (ret) return ret; - dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); + dp_ctrl_train_pattern_set(ctrl, pattern); for (tries = 0; tries <= maximum_retries; tries++) { drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); From ab8533946db7de7ff042bb2147acc3ec6da1bac1 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 4 Aug 2022 07:38:48 -0700 Subject: [PATCH 003/228] drm/msm/dsi: Fix number of regulators for msm8996_dsi_cfg [ Upstream commit 1e00d6ac8a3422765bae37aeac2002dfd3c0bda6 ] 3 regulators are listed but the number 2 is specified. Fix it. Fixes: 3a3ff88a0fc1 ("drm/msm/dsi: Add 8x96 info in dsi_cfg") Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/496318/ Link: https://lore.kernel.org/r/20220804073608.v4.1.I1056ee3f77f71287f333279efe4c85f88d403f65@changeid Signed-off-by: Abhinav Kumar Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 96bbc8b6d0092..2981dd7c79cc8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -109,7 +109,7 @@ static const char * const dsi_8996_bus_clk_names[] = { static const struct msm_dsi_config msm8996_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, .reg_cfg = { - .num = 2, + .num = 3, .regs = { {"vdda", 18160, 1 }, /* 1.25 V */ {"vcca", 17000, 32 }, /* 0.925 V */ From 1a785b435276b951d28b92411a4124fd2d88bd16 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 4 Aug 2022 07:38:49 -0700 Subject: [PATCH 004/228] drm/msm/dsi: Fix number of regulators for SDM660 [ Upstream commit a1653a75987749ba6dba94fa2e62f0f36b387d1a ] 1 regulator is listed but the number 2 is specified. This presumably means we try to get a regulator with no name. Fix it. Fixes: 462f7017a691 ("drm/msm/dsi: Fix DSI and DSI PHY regulator config from SDM660") Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Reviewed-by: Marijn Suijten Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/496323/ Link: https://lore.kernel.org/r/20220804073608.v4.2.I94b3c3e412b7c208061349f05659e126483171b1@changeid Signed-off-by: Abhinav Kumar Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 2981dd7c79cc8..ce3901439c69c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -148,7 +148,7 @@ static const char * const dsi_sdm660_bus_clk_names[] = { static const struct msm_dsi_config sdm660_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, .reg_cfg = { - .num = 2, + .num = 1, .regs = { {"vdda", 12560, 4 }, /* 1.2 V */ }, From 9e1f74294d539849917563555b783411be9ac84a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Aug 2022 14:37:31 +0300 Subject: [PATCH 005/228] platform/x86: pmc_atom: Fix SLP_TYPx bitfield mask [ Upstream commit 0a90ed8d0cfa29735a221eba14d9cb6c735d35b6 ] On Intel hardware the SLP_TYPx bitfield occupies bits 10-12 as per ACPI specification (see Table 4.13 "PM1 Control Registers Fixed Hardware Feature Control Bits" for the details). Fix the mask and other related definitions accordingly. Fixes: 93e5eadd1f6e ("x86/platform: New Intel Atom SOC power management controller driver") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220801113734.36131-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Sasha Levin --- drivers/platform/x86/pmc_atom.c | 2 +- include/linux/platform_data/x86/pmc_atom.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index a9d2a4b98e570..4b0739f95f8b9 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -244,7 +244,7 @@ static void pmc_power_off(void) pm1_cnt_port = acpi_base_addr + PM1_CNT; pm1_cnt_value = inl(pm1_cnt_port); - pm1_cnt_value &= SLEEP_TYPE_MASK; + pm1_cnt_value &= ~SLEEP_TYPE_MASK; pm1_cnt_value |= SLEEP_TYPE_S5; pm1_cnt_value |= SLEEP_ENABLE; diff --git a/include/linux/platform_data/x86/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h index 022bcea9edec5..99a9b09dc839d 100644 --- a/include/linux/platform_data/x86/pmc_atom.h +++ b/include/linux/platform_data/x86/pmc_atom.h @@ -7,6 +7,8 @@ #ifndef PMC_ATOM_H #define PMC_ATOM_H +#include + /* ValleyView Power Control Unit PCI Device ID */ #define PCI_DEVICE_ID_VLV_PMC 0x0F1C /* CherryTrail Power Control Unit PCI Device ID */ @@ -139,9 +141,9 @@ #define ACPI_MMIO_REG_LEN 0x100 #define PM1_CNT 0x4 -#define SLEEP_TYPE_MASK 0xFFFFECFF +#define SLEEP_TYPE_MASK GENMASK(12, 10) #define SLEEP_TYPE_S5 0x1C00 -#define SLEEP_ENABLE 0x2000 +#define SLEEP_ENABLE BIT(13) extern int pmc_atom_read(int offset, u32 *value); extern int pmc_atom_write(int offset, u32 value); From 7497f9766f08a05e7c5c939dd9542a01702df458 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Fri, 22 Jul 2022 15:07:18 +0200 Subject: [PATCH 006/228] iio: adc: mcp3911: make use of the sign bit [ Upstream commit 8f89e33bf040bbef66386c426198622180233178 ] The device supports negative values as well. Fixes: 3a89b289df5d ("iio: adc: add support for mcp3911") Signed-off-by: Marcus Folkesson Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220722130726.7627-2-marcus.folkesson@gmail.com Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/adc/mcp3911.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index e573da5397bb3..81eeb00842112 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -111,6 +111,8 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, if (ret) goto out; + *val = sign_extend32(*val, 23); + ret = IIO_VAL_INT; break; From de22cba333d8699ad77e79f862fe1320cb1284de Mon Sep 17 00:00:00 2001 From: Liu Jian Date: Tue, 9 Aug 2022 17:49:15 +0800 Subject: [PATCH 007/228] skmsg: Fix wrong last sg check in sk_msg_recvmsg() [ Upstream commit 583585e48d965338e73e1eb383768d16e0922d73 ] Fix one kernel NULL pointer dereference as below: [ 224.462334] Call Trace: [ 224.462394] __tcp_bpf_recvmsg+0xd3/0x380 [ 224.462441] ? sock_has_perm+0x78/0xa0 [ 224.462463] tcp_bpf_recvmsg+0x12e/0x220 [ 224.462494] inet_recvmsg+0x5b/0xd0 [ 224.462534] __sys_recvfrom+0xc8/0x130 [ 224.462574] ? syscall_trace_enter+0x1df/0x2e0 [ 224.462606] ? __do_page_fault+0x2de/0x500 [ 224.462635] __x64_sys_recvfrom+0x24/0x30 [ 224.462660] do_syscall_64+0x5d/0x1d0 [ 224.462709] entry_SYSCALL_64_after_hwframe+0x65/0xca In commit 9974d37ea75f ("skmsg: Fix invalid last sg check in sk_msg_recvmsg()"), we change last sg check to sg_is_last(), but in sockmap redirection case (without stream_parser/stream_verdict/ skb_verdict), we did not mark the end of the scatterlist. Check the sk_msg_alloc, sk_msg_page_add, and bpf_msg_push_data functions, they all do not mark the end of sg. They are expected to use sg.end for end judgment. So the judgment of '(i != msg_rx->sg.end)' is added back here. Fixes: 9974d37ea75f ("skmsg: Fix invalid last sg check in sk_msg_recvmsg()") Signed-off-by: Liu Jian Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Jakub Sitnicki Link: https://lore.kernel.org/bpf/20220809094915.150391-1-liujian56@huawei.com Signed-off-by: Sasha Levin --- net/core/skmsg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 4ddcfac344984..054073c7cbb95 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -462,7 +462,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, if (copied == len) break; - } while (!sg_is_last(sge)); + } while ((i != msg_rx->sg.end) && !sg_is_last(sge)); if (unlikely(peek)) { msg_rx = sk_psock_next_msg(psock, msg_rx); @@ -472,7 +472,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, } msg_rx->sg.start = i; - if (!sge->length && sg_is_last(sge)) { + if (!sge->length && (i == msg_rx->sg.end || sg_is_last(sge))) { msg_rx = sk_psock_dequeue_msg(psock); kfree_sk_msg(msg_rx); } From 1c518476ceb40eb36f258da97b956a48979bc0d1 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Tue, 16 Aug 2022 20:55:16 +0000 Subject: [PATCH 008/228] bpf: Restrict bpf_sys_bpf to CAP_PERFMON [ Upstream commit 14b20b784f59bdd95f6f1cfb112c9818bcec4d84 ] The verifier cannot perform sufficient validation of any pointers passed into bpf_attr and treats them as integers rather than pointers. The helper will then read from arbitrary pointers passed into it. Restrict the helper to CAP_PERFMON since the security model in BPF of arbitrary kernel read is CAP_BPF + CAP_PERFMON. Fixes: af2ac3e13e45 ("bpf: Prepare bpf syscall to be used from kernel and user space.") Signed-off-by: YiFei Zhu Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20220816205517.682470-1-zhuyifei@google.com Signed-off-by: Sasha Levin --- kernel/bpf/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 48e02a725563f..99ce46f518893 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4785,7 +4785,7 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_sys_bpf: - return &bpf_sys_bpf_proto; + return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto; case BPF_FUNC_btf_find_by_name_kind: return &bpf_btf_find_by_name_kind_proto; case BPF_FUNC_sys_close: From 222bd95c89b135fde21f0bd0cb5cc1611c0c576c Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 13 Aug 2022 21:40:30 +0800 Subject: [PATCH 009/228] bpf, cgroup: Fix kernel BUG in purge_effective_progs [ Upstream commit 7d6620f107bae6ed687ff07668e8e8f855487aa9 ] Syzkaller reported a triggered kernel BUG as follows: ------------[ cut here ]------------ kernel BUG at kernel/bpf/cgroup.c:925! invalid opcode: 0000 [#1] PREEMPT SMP NOPTI CPU: 1 PID: 194 Comm: detach Not tainted 5.19.0-14184-g69dac8e431af #8 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 RIP: 0010:__cgroup_bpf_detach+0x1f2/0x2a0 Code: 00 e8 92 60 30 00 84 c0 75 d8 4c 89 e0 31 f6 85 f6 74 19 42 f6 84 28 48 05 00 00 02 75 0e 48 8b 80 c0 00 00 00 48 85 c0 75 e5 <0f> 0b 48 8b 0c5 RSP: 0018:ffffc9000055bdb0 EFLAGS: 00000246 RAX: 0000000000000000 RBX: ffff888100ec0800 RCX: ffffc900000f1000 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff888100ec4578 RBP: 0000000000000000 R08: ffff888100ec0800 R09: 0000000000000040 R10: 0000000000000000 R11: 0000000000000000 R12: ffff888100ec4000 R13: 000000000000000d R14: ffffc90000199000 R15: ffff888100effb00 FS: 00007f68213d2b80(0000) GS:ffff88813bc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055f74a0e5850 CR3: 0000000102836000 CR4: 00000000000006e0 Call Trace: cgroup_bpf_prog_detach+0xcc/0x100 __sys_bpf+0x2273/0x2a00 __x64_sys_bpf+0x17/0x20 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f68214dbcb9 Code: 08 44 89 e0 5b 41 5c c3 66 0f 1f 84 00 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 ff8 RSP: 002b:00007ffeb487db68 EFLAGS: 00000246 ORIG_RAX: 0000000000000141 RAX: ffffffffffffffda RBX: 000000000000000b RCX: 00007f68214dbcb9 RDX: 0000000000000090 RSI: 00007ffeb487db70 RDI: 0000000000000009 RBP: 0000000000000003 R08: 0000000000000012 R09: 0000000b00000003 R10: 00007ffeb487db70 R11: 0000000000000246 R12: 00007ffeb487dc20 R13: 0000000000000004 R14: 0000000000000001 R15: 000055f74a1011b0 Modules linked in: ---[ end trace 0000000000000000 ]--- Repetition steps: For the following cgroup tree, root | cg1 | cg2 1. attach prog2 to cg2, and then attach prog1 to cg1, both bpf progs attach type is NONE or OVERRIDE. 2. write 1 to /proc/thread-self/fail-nth for failslab. 3. detach prog1 for cg1, and then kernel BUG occur. Failslab injection will cause kmalloc fail and fall back to purge_effective_progs. The problem is that cg2 have attached another prog, so when go through cg2 layer, iteration will add pos to 1, and subsequent operations will be skipped by the following condition, and cg will meet NULL in the end. `if (pos && !(cg->bpf.flags[atype] & BPF_F_ALLOW_MULTI))` The NULL cg means no link or prog match, this is as expected, and it's not a bug. So here just skip the no match situation. Fixes: 4c46091ee985 ("bpf: Fix KASAN use-after-free Read in compute_effective_progs") Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220813134030.1972696-1-pulehui@huawei.com Signed-off-by: Sasha Levin --- kernel/bpf/cgroup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 565e4c59db660..eb3e787a3a977 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -709,8 +709,10 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog, pos++; } } + + /* no link or prog match, skip the cgroup of this layer */ + continue; found: - BUG_ON(!cg); progs = rcu_dereference_protected( desc->bpf.effective[atype], lockdep_is_held(&cgroup_mutex)); From 9f8558c5c642c62c450c98c99b7d18a709fff485 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 8 Aug 2022 11:42:24 +0800 Subject: [PATCH 010/228] ieee802154/adf7242: defer destroy_workqueue call [ Upstream commit afe7116f6d3b888778ed6d95e3cf724767b9aedf ] There is a possible race condition (use-after-free) like below (FREE) | (USE) adf7242_remove | adf7242_channel cancel_delayed_work_sync | destroy_workqueue (1) | adf7242_cmd_rx | mod_delayed_work (2) | The root cause for this race is that the upper layer (ieee802154) is unaware of this detaching event and the function adf7242_channel can be called without any checks. To fix this, we can add a flag write at the beginning of adf7242_remove and add flag check in adf7242_channel. Or we can just defer the destructive operation like other commit 3e0588c291d6 ("hamradio: defer ax25 kfree after unregister_netdev") which let the ieee802154_unregister_hw() to handle the synchronization. This patch takes the second option. Fixes: 58e9683d1475 ("net: ieee802154: adf7242: Fix OCL calibration runs") Signed-off-by: Lin Ma Acked-by: Michael Hennerich Link: https://lore.kernel.org/r/20220808034224.12642-1-linma@zju.edu.cn Signed-off-by: Stefan Schmidt Signed-off-by: Sasha Levin --- drivers/net/ieee802154/adf7242.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index 7db9cbd0f5ded..07adbeec19787 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c @@ -1310,10 +1310,11 @@ static int adf7242_remove(struct spi_device *spi) debugfs_remove_recursive(lp->debugfs_root); + ieee802154_unregister_hw(lp->hw); + cancel_delayed_work_sync(&lp->work); destroy_workqueue(lp->wqueue); - ieee802154_unregister_hw(lp->hw); mutex_destroy(&lp->bmux); ieee802154_free_hw(lp->hw); From 630ab29120b5dd1c543150da5e1aa304a5aece2e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 25 Aug 2021 14:06:50 +0300 Subject: [PATCH 011/228] drm/i915/backlight: extract backlight code to a separate file [ Upstream commit 6cc42fbeb150ff33b17cbf108713ca4be23994d8 ] In a long overdue refactoring, split out backlight code to new intel_backlight.[ch]. Simple code movement, leave renames for follow-up work. No functional changes. Cc: Lyude Paul Reviewed-by: Lyude Paul Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/97d310848f03061473b9b2328e2c5c4dcf263cfa.1629888677.git.jani.nikula@intel.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/g4x_dp.c | 2 +- drivers/gpu/drm/i915/display/icl_dsi.c | 1 + .../gpu/drm/i915/display/intel_backlight.c | 1778 +++++++++++++++++ .../gpu/drm/i915/display/intel_backlight.h | 51 + .../gpu/drm/i915/display/intel_connector.c | 4 +- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- drivers/gpu/drm/i915/display/intel_dp.c | 1 + .../drm/i915/display/intel_dp_aux_backlight.c | 2 +- drivers/gpu/drm/i915/display/intel_lvds.c | 1 + drivers/gpu/drm/i915/display/intel_opregion.c | 3 +- drivers/gpu/drm/i915/display/intel_panel.c | 1767 +--------------- drivers/gpu/drm/i915/display/intel_panel.h | 34 +- drivers/gpu/drm/i915/display/vlv_dsi.c | 1 + 14 files changed, 1843 insertions(+), 1805 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_backlight.c create mode 100644 drivers/gpu/drm/i915/display/intel_backlight.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 26cf754229451..9d371be7dc5cd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -249,6 +249,7 @@ i915-y += \ display/g4x_dp.o \ display/g4x_hdmi.o \ display/icl_dsi.o \ + display/intel_backlight.o \ display/intel_crt.o \ display/intel_ddi.o \ display/intel_ddi_buf_trans.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index de0f358184aa3..29c0eca647e34 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -7,6 +7,7 @@ #include "g4x_dp.h" #include "intel_audio.h" +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" @@ -16,7 +17,6 @@ #include "intel_fifo_underrun.h" #include "intel_hdmi.h" #include "intel_hotplug.h" -#include "intel_panel.h" #include "intel_pps.h" #include "intel_sideband.h" diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 638a00b2dc2d2..2601873e15466 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -29,6 +29,7 @@ #include #include "intel_atomic.h" +#include "intel_backlight.h" #include "intel_combo_phy.h" #include "intel_connector.h" #include "intel_crtc.h" diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c new file mode 100644 index 0000000000000..4b0086ee48519 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -0,0 +1,1778 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include +#include + +#include "intel_backlight.h" +#include "intel_connector.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "intel_dp_aux_backlight.h" +#include "intel_dsi_dcs_backlight.h" +#include "intel_panel.h" + +/** + * scale - scale values from one range to another + * @source_val: value in range [@source_min..@source_max] + * @source_min: minimum legal value for @source_val + * @source_max: maximum legal value for @source_val + * @target_min: corresponding target value for @source_min + * @target_max: corresponding target value for @source_max + * + * Return @source_val in range [@source_min..@source_max] scaled to range + * [@target_min..@target_max]. + */ +static u32 scale(u32 source_val, + u32 source_min, u32 source_max, + u32 target_min, u32 target_max) +{ + u64 target_val; + + WARN_ON(source_min > source_max); + WARN_ON(target_min > target_max); + + /* defensive */ + source_val = clamp(source_val, source_min, source_max); + + /* avoid overflows */ + target_val = mul_u32_u32(source_val - source_min, + target_max - target_min); + target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min); + target_val += target_min; + + return target_val; +} + +/* + * Scale user_level in range [0..user_max] to [0..hw_max], clamping the result + * to [hw_min..hw_max]. + */ +static u32 clamp_user_to_hw(struct intel_connector *connector, + u32 user_level, u32 user_max) +{ + struct intel_panel *panel = &connector->panel; + u32 hw_level; + + hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); + hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); + + return hw_level; +} + +/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ +static u32 scale_hw_to_user(struct intel_connector *connector, + u32 hw_level, u32 user_max) +{ + struct intel_panel *panel = &connector->panel; + + return scale(hw_level, panel->backlight.min, panel->backlight.max, + 0, user_max); +} + +u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); + + if (dev_priv->params.invert_brightness < 0) + return val; + + if (dev_priv->params.invert_brightness > 0 || + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { + return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; + } + + return val; +} + +void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val); + panel->backlight.pwm_funcs->set(conn_state, val); +} + +u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + drm_WARN_ON_ONCE(&dev_priv->drm, + panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); + + val = scale(val, panel->backlight.min, panel->backlight.max, + panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); + + return intel_panel_invert_pwm_level(connector, val); +} + +u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + drm_WARN_ON_ONCE(&dev_priv->drm, + panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); + + if (dev_priv->params.invert_brightness > 0 || + (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)) + val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min); + + return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max, + panel->backlight.min, panel->backlight.max); +} + +static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 val; + + val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + if (DISPLAY_VER(dev_priv) < 4) + val >>= 1; + + if (panel->backlight.combination_mode) { + u8 lbpc; + + pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc); + val *= lbpc; + } + + return val; +} + +static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) + return 0; + + return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + return intel_de_read(dev_priv, + BXT_BLC_PWM_DUTY(panel->backlight.controller)); +} + +static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct intel_panel *panel = &connector->panel; + struct pwm_state state; + + pwm_get_state(panel->backlight.pwm, &state); + return pwm_get_relative_duty_cycle(&state, 100); +} + +static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; + intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level); +} + +static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u32 tmp; + + tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level); +} + +static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 tmp, mask; + + drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); + + if (panel->backlight.combination_mode) { + u8 lbpc; + + lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1; + level /= lbpc; + pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); + } + + if (DISPLAY_VER(dev_priv) == 4) { + mask = BACKLIGHT_DUTY_CYCLE_MASK; + } else { + level <<= 1; + mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; + } + + tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask; + intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level); +} + +static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; + u32 tmp; + + tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; + intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level); +} + +static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + intel_de_write(dev_priv, + BXT_BLC_PWM_DUTY(panel->backlight.controller), level); +} + +static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); + pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +} + +static void +intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level); + + panel->backlight.funcs->set(conn_state, level); +} + +/* set backlight brightness to level in range [0..max], assuming hw min is + * respected. + */ +void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, + u32 user_level, u32 user_max) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 hw_level; + + /* + * Lack of crtc may occur during driver init because + * connection_mutex isn't held across the entire backlight + * setup + modeset readout, and the BIOS can issue the + * requests at any time. + */ + if (!panel->backlight.present || !conn_state->crtc) + return; + + mutex_lock(&dev_priv->backlight_lock); + + drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); + + hw_level = clamp_user_to_hw(connector, user_level, user_max); + panel->backlight.level = hw_level; + + if (panel->backlight.device) + panel->backlight.device->props.brightness = + scale_hw_to_user(connector, + panel->backlight.level, + panel->backlight.device->props.max_brightness); + + if (panel->backlight.enabled) + intel_panel_actually_set_backlight(conn_state, hw_level); + + mutex_unlock(&dev_priv->backlight_lock); +} + +static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, level); + + /* + * Although we don't support or enable CPU PWM with LPT/SPT based + * systems, it may have been enabled prior to loading the + * driver. Disable to avoid warnings on LCPLL disable. + * + * This needs rework if we need to add support for CPU PWM on PCH split + * platforms. + */ + tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); + if (tmp & BLM_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, + "cpu backlight was enabled, disabling\n"); + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, + tmp & ~BLM_PWM_ENABLE); + } + + tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +} + +static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, val); + + tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); + + tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +} + +static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + intel_panel_set_pwm_level(old_conn_state, val); +} + +static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev); + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, val); + + tmp = intel_de_read(dev_priv, BLC_PWM_CTL2); + intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); +} + +static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe; + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, val); + + tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); + intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), + tmp & ~BLM_PWM_ENABLE); +} + +static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, val); + + tmp = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + tmp & ~BXT_BLC_PWM_ENABLE); + + if (panel->backlight.controller == 1) { + val = intel_de_read(dev_priv, UTIL_PIN_CTL); + val &= ~UTIL_PIN_ENABLE; + intel_de_write(dev_priv, UTIL_PIN_CTL, val); + } +} + +static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 tmp; + + intel_panel_set_pwm_level(old_conn_state, val); + + tmp = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + tmp & ~BXT_BLC_PWM_ENABLE); +} + +static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct intel_panel *panel = &connector->panel; + + panel->backlight.pwm_state.enabled = false; + pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +} + +void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + if (!panel->backlight.present) + return; + + /* + * Do not disable backlight on the vga_switcheroo path. When switching + * away from i915, the other client may depend on i915 to handle the + * backlight. This will leave the backlight on unnecessarily when + * another client is not activated. + */ + if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) { + drm_dbg_kms(&dev_priv->drm, + "Skipping backlight disable on vga switch\n"); + return; + } + + mutex_lock(&dev_priv->backlight_lock); + + if (panel->backlight.device) + panel->backlight.device->props.power = FB_BLANK_POWERDOWN; + panel->backlight.enabled = false; + panel->backlight.funcs->disable(old_conn_state, 0); + + mutex_unlock(&dev_priv->backlight_lock); +} + +static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 pch_ctl1, pch_ctl2, schicken; + + pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); + } + + if (HAS_PCH_LPT(dev_priv)) { + schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2); + if (panel->backlight.alternate_pwm_increment) + schicken |= LPT_PWM_GRANULARITY; + else + schicken &= ~LPT_PWM_GRANULARITY; + intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken); + } else { + schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1); + if (panel->backlight.alternate_pwm_increment) + schicken |= SPT_PWM_GRANULARITY; + else + schicken &= ~SPT_PWM_GRANULARITY; + intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken); + } + + pch_ctl2 = panel->backlight.pwm_level_max << 16; + intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); + + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + /* After LPT, override is the default. */ + if (HAS_PCH_LPT(dev_priv)) + pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; + + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); + intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, + pch_ctl1 | BLM_PCH_PWM_ENABLE); + + /* This won't stick until the above enable. */ + intel_panel_set_pwm_level(conn_state, level); +} + +static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 cpu_ctl2, pch_ctl1, pch_ctl2; + + cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); + if (cpu_ctl2 & BLM_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n"); + cpu_ctl2 &= ~BLM_PWM_ENABLE; + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); + } + + pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); + } + + if (cpu_transcoder == TRANSCODER_EDP) + cpu_ctl2 = BLM_TRANSCODER_EDP; + else + cpu_ctl2 = BLM_PIPE(cpu_transcoder); + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); + intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2); + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); + + /* This won't stick until the above enable. */ + intel_panel_set_pwm_level(conn_state, level); + + pch_ctl2 = panel->backlight.pwm_level_max << 16; + intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); + + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); + intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, + pch_ctl1 | BLM_PCH_PWM_ENABLE); +} + +static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 ctl, freq; + + ctl = intel_de_read(dev_priv, BLC_PWM_CTL); + if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { + drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); + intel_de_write(dev_priv, BLC_PWM_CTL, 0); + } + + freq = panel->backlight.pwm_level_max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 17; + if (panel->backlight.combination_mode) + ctl |= BLM_LEGACY_MODE; + if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm) + ctl |= BLM_POLARITY_PNV; + + intel_de_write(dev_priv, BLC_PWM_CTL, ctl); + intel_de_posting_read(dev_priv, BLC_PWM_CTL); + + /* XXX: combine this into above write? */ + intel_panel_set_pwm_level(conn_state, level); + + /* + * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is + * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 + * that has backlight. + */ + if (DISPLAY_VER(dev_priv) == 2) + intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); +} + +static void i965_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; + u32 ctl, ctl2, freq; + + ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); + if (ctl2 & BLM_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); + } + + freq = panel->backlight.pwm_level_max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 16; + intel_de_write(dev_priv, BLC_PWM_CTL, ctl); + + ctl2 = BLM_PIPE(pipe); + if (panel->backlight.combination_mode) + ctl2 |= BLM_COMBINATION_MODE; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); + intel_de_posting_read(dev_priv, BLC_PWM_CTL2); + intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); + + intel_panel_set_pwm_level(conn_state, level); +} + +static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; + u32 ctl, ctl2; + + ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); + if (ctl2 & BLM_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); + } + + ctl = panel->backlight.pwm_level_max << 16; + intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl); + + /* XXX: combine this into above write? */ + intel_panel_set_pwm_level(conn_state, level); + + ctl2 = 0; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); + intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); + intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), + ctl2 | BLM_PWM_ENABLE); +} + +static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; + u32 pwm_ctl, val; + + /* Controller 1 uses the utility pin. */ + if (panel->backlight.controller == 1) { + val = intel_de_read(dev_priv, UTIL_PIN_CTL); + if (val & UTIL_PIN_ENABLE) { + drm_dbg_kms(&dev_priv->drm, + "util pin already enabled\n"); + val &= ~UTIL_PIN_ENABLE; + intel_de_write(dev_priv, UTIL_PIN_CTL, val); + } + + val = 0; + if (panel->backlight.util_pin_active_low) + val |= UTIL_PIN_POLARITY; + intel_de_write(dev_priv, UTIL_PIN_CTL, + val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); + } + + pwm_ctl = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + if (pwm_ctl & BXT_BLC_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); + pwm_ctl &= ~BXT_BLC_PWM_ENABLE; + intel_de_write(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl); + } + + intel_de_write(dev_priv, + BXT_BLC_PWM_FREQ(panel->backlight.controller), + panel->backlight.pwm_level_max); + + intel_panel_set_pwm_level(conn_state, level); + + pwm_ctl = 0; + if (panel->backlight.active_low_pwm) + pwm_ctl |= BXT_BLC_PWM_POLARITY; + + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl); + intel_de_posting_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl | BXT_BLC_PWM_ENABLE); +} + +static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl; + + pwm_ctl = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + if (pwm_ctl & BXT_BLC_PWM_ENABLE) { + drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); + pwm_ctl &= ~BXT_BLC_PWM_ENABLE; + intel_de_write(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl); + } + + intel_de_write(dev_priv, + BXT_BLC_PWM_FREQ(panel->backlight.controller), + panel->backlight.pwm_level_max); + + intel_panel_set_pwm_level(conn_state, level); + + pwm_ctl = 0; + if (panel->backlight.active_low_pwm) + pwm_ctl |= BXT_BLC_PWM_POLARITY; + + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl); + intel_de_posting_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl | BXT_BLC_PWM_ENABLE); +} + +static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); + panel->backlight.pwm_state.enabled = true; + pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); +} + +static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + + WARN_ON(panel->backlight.max == 0); + + if (panel->backlight.level <= panel->backlight.min) { + panel->backlight.level = panel->backlight.max; + if (panel->backlight.device) + panel->backlight.device->props.brightness = + scale_hw_to_user(connector, + panel->backlight.level, + panel->backlight.device->props.max_brightness); + } + + panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level); + panel->backlight.enabled = true; + if (panel->backlight.device) + panel->backlight.device->props.power = FB_BLANK_UNBLANK; +} + +void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; + + if (!panel->backlight.present) + return; + + drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe)); + + mutex_lock(&dev_priv->backlight_lock); + + __intel_panel_enable_backlight(crtc_state, conn_state); + + mutex_unlock(&dev_priv->backlight_lock); +} + +#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +static u32 intel_panel_get_backlight(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 val = 0; + + mutex_lock(&dev_priv->backlight_lock); + + if (panel->backlight.enabled) + val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector)); + + mutex_unlock(&dev_priv->backlight_lock); + + drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val); + return val; +} + +/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ +static u32 scale_user_to_hw(struct intel_connector *connector, + u32 user_level, u32 user_max) +{ + struct intel_panel *panel = &connector->panel; + + return scale(user_level, 0, user_max, + panel->backlight.min, panel->backlight.max); +} + +/* set backlight brightness to level in range [0..max], scaling wrt hw min */ +static void intel_panel_set_backlight(const struct drm_connector_state *conn_state, + u32 user_level, u32 user_max) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 hw_level; + + if (!panel->backlight.present) + return; + + mutex_lock(&dev_priv->backlight_lock); + + drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); + + hw_level = scale_user_to_hw(connector, user_level, user_max); + panel->backlight.level = hw_level; + + if (panel->backlight.enabled) + intel_panel_actually_set_backlight(conn_state, hw_level); + + mutex_unlock(&dev_priv->backlight_lock); +} + +static int intel_backlight_device_update_status(struct backlight_device *bd) +{ + struct intel_connector *connector = bl_get_data(bd); + struct intel_panel *panel = &connector->panel; + struct drm_device *dev = connector->base.dev; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", + bd->props.brightness, bd->props.max_brightness); + intel_panel_set_backlight(connector->base.state, bd->props.brightness, + bd->props.max_brightness); + + /* + * Allow flipping bl_power as a sub-state of enabled. Sadly the + * backlight class device does not make it easy to differentiate + * between callbacks for brightness and bl_power, so our backlight_power + * callback needs to take this into account. + */ + if (panel->backlight.enabled) { + if (panel->backlight.power) { + bool enable = bd->props.power == FB_BLANK_UNBLANK && + bd->props.brightness != 0; + panel->backlight.power(connector, enable); + } + } else { + bd->props.power = FB_BLANK_POWERDOWN; + } + + drm_modeset_unlock(&dev->mode_config.connection_mutex); + return 0; +} + +static int intel_backlight_device_get_brightness(struct backlight_device *bd) +{ + struct intel_connector *connector = bl_get_data(bd); + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + intel_wakeref_t wakeref; + int ret = 0; + + with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) { + u32 hw_level; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + hw_level = intel_panel_get_backlight(connector); + ret = scale_hw_to_user(connector, + hw_level, bd->props.max_brightness); + + drm_modeset_unlock(&dev->mode_config.connection_mutex); + } + + return ret; +} + +static const struct backlight_ops intel_backlight_device_ops = { + .update_status = intel_backlight_device_update_status, + .get_brightness = intel_backlight_device_get_brightness, +}; + +int intel_backlight_device_register(struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + struct backlight_properties props; + struct backlight_device *bd; + const char *name; + int ret = 0; + + if (WARN_ON(panel->backlight.device)) + return -ENODEV; + + if (!panel->backlight.present) + return 0; + + WARN_ON(panel->backlight.max == 0); + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + + /* + * Note: Everything should work even if the backlight device max + * presented to the userspace is arbitrarily chosen. + */ + props.max_brightness = panel->backlight.max; + props.brightness = scale_hw_to_user(connector, + panel->backlight.level, + props.max_brightness); + + if (panel->backlight.enabled) + props.power = FB_BLANK_UNBLANK; + else + props.power = FB_BLANK_POWERDOWN; + + name = kstrdup("intel_backlight", GFP_KERNEL); + if (!name) + return -ENOMEM; + + bd = backlight_device_register(name, connector->base.kdev, connector, + &intel_backlight_device_ops, &props); + + /* + * Using the same name independent of the drm device or connector + * prevents registration of multiple backlight devices in the + * driver. However, we need to use the default name for backward + * compatibility. Use unique names for subsequent backlight devices as a + * fallback when the default name already exists. + */ + if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) { + kfree(name); + name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", + i915->drm.primary->index, connector->base.name); + if (!name) + return -ENOMEM; + + bd = backlight_device_register(name, connector->base.kdev, connector, + &intel_backlight_device_ops, &props); + } + + if (IS_ERR(bd)) { + drm_err(&i915->drm, + "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n", + connector->base.base.id, connector->base.name, name, PTR_ERR(bd)); + ret = PTR_ERR(bd); + goto out; + } + + panel->backlight.device = bd; + + drm_dbg_kms(&i915->drm, + "[CONNECTOR:%d:%s] backlight device %s registered\n", + connector->base.base.id, connector->base.name, name); + +out: + kfree(name); + + return ret; +} + +void intel_backlight_device_unregister(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + if (panel->backlight.device) { + backlight_device_unregister(panel->backlight.device); + panel->backlight.device = NULL; + } +} +#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + +/* + * CNP: PWM clock frequency is 19.2 MHz or 24 MHz. + * PWM increment = 1 + */ +static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), + pwm_freq_hz); +} + +/* + * BXT: PWM clock frequency = 19.2 MHz. + */ +static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz); +} + +/* + * SPT: This value represents the period of the PWM stream in clock periods + * multiplied by 16 (default increment) or 128 (alternate increment selected in + * SCHICKEN_1 bit 0). PWM clock is 24 MHz. + */ +static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct intel_panel *panel = &connector->panel; + u32 mul; + + if (panel->backlight.alternate_pwm_increment) + mul = 128; + else + mul = 16; + + return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul); +} + +/* + * LPT: This value represents the period of the PWM stream in clock periods + * multiplied by 128 (default increment) or 16 (alternate increment, selected in + * LPT SOUTH_CHICKEN2 register bit 5). + */ +static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 mul, clock; + + if (panel->backlight.alternate_pwm_increment) + mul = 16; + else + mul = 128; + + if (HAS_PCH_LPT_H(dev_priv)) + clock = MHz(135); /* LPT:H */ + else + clock = MHz(24); /* LPT:LP */ + + return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); +} + +/* + * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH + * display raw clocks multiplied by 128. + */ +static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), + pwm_freq_hz * 128); +} + +/* + * Gen2: This field determines the number of time base events (display core + * clock frequency/32) in total for a complete cycle of modulated backlight + * control. + * + * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) + * divided by 32. + */ +static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + int clock; + + if (IS_PINEVIEW(dev_priv)) + clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); + else + clock = KHz(dev_priv->cdclk.hw.cdclk); + + return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32); +} + +/* + * Gen4: This value represents the period of the PWM stream in display core + * clocks ([DevCTG] HRAW clocks) multiplied by 128. + * + */ +static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + int clock; + + if (IS_G4X(dev_priv)) + clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); + else + clock = KHz(dev_priv->cdclk.hw.cdclk); + + return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128); +} + +/* + * VLV: This value represents the period of the PWM stream in display core + * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks + * multiplied by 16. CHV uses a 19.2MHz S0IX clock. + */ +static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + int mul, clock; + + if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) { + if (IS_CHERRYVIEW(dev_priv)) + clock = KHz(19200); + else + clock = MHz(25); + mul = 16; + } else { + clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); + mul = 128; + } + + return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); +} + +static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv) +{ + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (pwm_freq_hz) { + drm_dbg_kms(&dev_priv->drm, + "VBT defined backlight frequency %u Hz\n", + pwm_freq_hz); + } else { + pwm_freq_hz = 200; + drm_dbg_kms(&dev_priv->drm, + "default backlight frequency %u Hz\n", + pwm_freq_hz); + } + + return pwm_freq_hz; +} + +static u32 get_backlight_max_vbt(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv); + u32 pwm; + + if (!panel->backlight.pwm_funcs->hz_to_pwm) { + drm_dbg_kms(&dev_priv->drm, + "backlight frequency conversion not supported\n"); + return 0; + } + + pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz); + if (!pwm) { + drm_dbg_kms(&dev_priv->drm, + "backlight frequency conversion failed\n"); + return 0; + } + + return pwm; +} + +/* + * Note: The setup hooks can't assume pipe is set! + */ +static u32 get_backlight_min_vbt(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + int min; + + drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); + + /* + * XXX: If the vbt value is 255, it makes min equal to max, which leads + * to problems. There are such machines out there. Either our + * interpretation is wrong or the vbt has bogus data. Or both. Safeguard + * against this by letting the minimum be at most (arbitrarily chosen) + * 25% of the max. + */ + min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); + if (min != dev_priv->vbt.backlight.min_brightness) { + drm_dbg_kms(&dev_priv->drm, + "clamping VBT min backlight %d/255 to %d/255\n", + dev_priv->vbt.backlight.min_brightness, min); + } + + /* vbt value is a coefficient in range [0..255] */ + return scale(min, 0, 255, 0, panel->backlight.pwm_level_max); +} + +static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; + bool alt, cpu_mode; + + if (HAS_PCH_LPT(dev_priv)) + alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY; + else + alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY; + panel->backlight.alternate_pwm_increment = alt; + + pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); + panel->backlight.pwm_level_max = pch_ctl2 >> 16; + + cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE; + + cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) && + !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) && + (cpu_ctl2 & BLM_PWM_ENABLE); + + if (cpu_mode) { + val = pch_get_backlight(connector, unused); + + drm_dbg_kms(&dev_priv->drm, + "CPU backlight register was enabled, switching to PCH override\n"); + + /* Write converted CPU PWM value to PCH override register */ + lpt_set_backlight(connector->base.state, val); + intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, + pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE); + + intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, + cpu_ctl2 & ~BLM_PWM_ENABLE); + } + + return 0; +} + +static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 cpu_ctl2, pch_ctl1, pch_ctl2; + + pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); + panel->backlight.pwm_level_max = pch_ctl2 >> 16; + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); + panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && + (pch_ctl1 & BLM_PCH_PWM_ENABLE); + + return 0; +} + +static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 ctl, val; + + ctl = intel_de_read(dev_priv, BLC_PWM_CTL); + + if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) + panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; + + if (IS_PINEVIEW(dev_priv)) + panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; + + panel->backlight.pwm_level_max = ctl >> 17; + + if (!panel->backlight.pwm_level_max) { + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + panel->backlight.pwm_level_max >>= 1; + } + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + if (panel->backlight.combination_mode) + panel->backlight.pwm_level_max *= 0xff; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + val = i9xx_get_backlight(connector, unused); + val = intel_panel_invert_pwm_level(connector, val); + val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); + + panel->backlight.pwm_enabled = val != 0; + + return 0; +} + +static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 ctl, ctl2; + + ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); + panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = intel_de_read(dev_priv, BLC_PWM_CTL); + panel->backlight.pwm_level_max = ctl >> 16; + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + if (panel->backlight.combination_mode) + panel->backlight.pwm_level_max *= 0xff; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; + + return 0; +} + +static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 ctl, ctl2; + + if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) + return -ENODEV; + + ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)); + panel->backlight.pwm_level_max = ctl >> 16; + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; + + return 0; +} + +static int +bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl, val; + + panel->backlight.controller = dev_priv->vbt.backlight.controller; + + pwm_ctl = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + + /* Controller 1 uses the utility pin. */ + if (panel->backlight.controller == 1) { + val = intel_de_read(dev_priv, UTIL_PIN_CTL); + panel->backlight.util_pin_active_low = + val & UTIL_PIN_POLARITY; + } + + panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; + panel->backlight.pwm_level_max = + intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; + + return 0; +} + +static int +cnp_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl; + + /* + * CNP has the BXT implementation of backlight, but with only one + * controller. TODO: ICP has multiple controllers but we only use + * controller 0 for now. + */ + panel->backlight.controller = 0; + + pwm_ctl = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); + + panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; + panel->backlight.pwm_level_max = + intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); + + if (!panel->backlight.pwm_level_max) + panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); + + if (!panel->backlight.pwm_level_max) + return -ENODEV; + + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; + + return 0; +} + +static int ext_pwm_setup_backlight(struct intel_connector *connector, + enum pipe pipe) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_panel *panel = &connector->panel; + const char *desc; + u32 level; + + /* Get the right PWM chip for DSI backlight according to VBT */ + if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { + panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight"); + desc = "PMIC"; + } else { + panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight"); + desc = "SoC"; + } + + if (IS_ERR(panel->backlight.pwm)) { + drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n", + desc); + panel->backlight.pwm = NULL; + return -ENODEV; + } + + panel->backlight.pwm_level_max = 100; /* 100% */ + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); + + if (pwm_is_enabled(panel->backlight.pwm)) { + /* PWM is already enabled, use existing settings */ + pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state); + + level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state, + 100); + level = intel_panel_invert_pwm_level(connector, level); + panel->backlight.pwm_enabled = true; + + drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n", + NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period, + get_vbt_pwm_freq(dev_priv), level); + } else { + /* Set period from VBT frequency, leave other settings at 0. */ + panel->backlight.pwm_state.period = + NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv); + } + + drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n", + desc); + return 0; +} + +static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + + panel->backlight.pwm_funcs->set(conn_state, + intel_panel_invert_pwm_level(connector, level)); +} + +static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe) +{ + struct intel_panel *panel = &connector->panel; + + return intel_panel_invert_pwm_level(connector, + panel->backlight.pwm_funcs->get(connector, pipe)); +} + +static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + + panel->backlight.pwm_funcs->enable(crtc_state, conn_state, + intel_panel_invert_pwm_level(connector, level)); +} + +static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + + panel->backlight.pwm_funcs->disable(conn_state, + intel_panel_invert_pwm_level(connector, level)); +} + +static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe) +{ + struct intel_panel *panel = &connector->panel; + int ret = panel->backlight.pwm_funcs->setup(connector, pipe); + + if (ret < 0) + return ret; + + panel->backlight.min = panel->backlight.pwm_level_min; + panel->backlight.max = panel->backlight.pwm_level_max; + panel->backlight.level = intel_pwm_get_backlight(connector, pipe); + panel->backlight.enabled = panel->backlight.pwm_enabled; + + return 0; +} + +void intel_panel_update_backlight(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; + + if (!panel->backlight.present) + return; + + mutex_lock(&dev_priv->backlight_lock); + if (!panel->backlight.enabled) + __intel_panel_enable_backlight(crtc_state, conn_state); + + mutex_unlock(&dev_priv->backlight_lock); +} + +int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + int ret; + + if (!dev_priv->vbt.backlight.present) { + if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { + drm_dbg_kms(&dev_priv->drm, + "no backlight present per VBT, but present per quirk\n"); + } else { + drm_dbg_kms(&dev_priv->drm, + "no backlight present per VBT\n"); + return 0; + } + } + + /* ensure intel_panel has been initialized first */ + if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs)) + return -ENODEV; + + /* set level and max in panel struct */ + mutex_lock(&dev_priv->backlight_lock); + ret = panel->backlight.funcs->setup(intel_connector, pipe); + mutex_unlock(&dev_priv->backlight_lock); + + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "failed to setup backlight for connector %s\n", + connector->name); + return ret; + } + + panel->backlight.present = true; + + drm_dbg_kms(&dev_priv->drm, + "Connector %s backlight initialized, %s, brightness %u/%u\n", + connector->name, + enableddisabled(panel->backlight.enabled), + panel->backlight.level, panel->backlight.max); + + return 0; +} + +void intel_panel_destroy_backlight(struct intel_panel *panel) +{ + /* dispose of the pwm */ + if (panel->backlight.pwm) + pwm_put(panel->backlight.pwm); + + panel->backlight.present = false; +} + +static const struct intel_panel_bl_funcs bxt_pwm_funcs = { + .setup = bxt_setup_backlight, + .enable = bxt_enable_backlight, + .disable = bxt_disable_backlight, + .set = bxt_set_backlight, + .get = bxt_get_backlight, + .hz_to_pwm = bxt_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs cnp_pwm_funcs = { + .setup = cnp_setup_backlight, + .enable = cnp_enable_backlight, + .disable = cnp_disable_backlight, + .set = bxt_set_backlight, + .get = bxt_get_backlight, + .hz_to_pwm = cnp_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs lpt_pwm_funcs = { + .setup = lpt_setup_backlight, + .enable = lpt_enable_backlight, + .disable = lpt_disable_backlight, + .set = lpt_set_backlight, + .get = lpt_get_backlight, + .hz_to_pwm = lpt_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs spt_pwm_funcs = { + .setup = lpt_setup_backlight, + .enable = lpt_enable_backlight, + .disable = lpt_disable_backlight, + .set = lpt_set_backlight, + .get = lpt_get_backlight, + .hz_to_pwm = spt_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs pch_pwm_funcs = { + .setup = pch_setup_backlight, + .enable = pch_enable_backlight, + .disable = pch_disable_backlight, + .set = pch_set_backlight, + .get = pch_get_backlight, + .hz_to_pwm = pch_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs ext_pwm_funcs = { + .setup = ext_pwm_setup_backlight, + .enable = ext_pwm_enable_backlight, + .disable = ext_pwm_disable_backlight, + .set = ext_pwm_set_backlight, + .get = ext_pwm_get_backlight, +}; + +static const struct intel_panel_bl_funcs vlv_pwm_funcs = { + .setup = vlv_setup_backlight, + .enable = vlv_enable_backlight, + .disable = vlv_disable_backlight, + .set = vlv_set_backlight, + .get = vlv_get_backlight, + .hz_to_pwm = vlv_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs i965_pwm_funcs = { + .setup = i965_setup_backlight, + .enable = i965_enable_backlight, + .disable = i965_disable_backlight, + .set = i9xx_set_backlight, + .get = i9xx_get_backlight, + .hz_to_pwm = i965_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs i9xx_pwm_funcs = { + .setup = i9xx_setup_backlight, + .enable = i9xx_enable_backlight, + .disable = i9xx_disable_backlight, + .set = i9xx_set_backlight, + .get = i9xx_get_backlight, + .hz_to_pwm = i9xx_hz_to_pwm, +}; + +static const struct intel_panel_bl_funcs pwm_bl_funcs = { + .setup = intel_pwm_setup_backlight, + .enable = intel_pwm_enable_backlight, + .disable = intel_pwm_disable_backlight, + .set = intel_pwm_set_backlight, + .get = intel_pwm_get_backlight, +}; + +/* Set up chip specific backlight functions */ +void +intel_panel_init_backlight_funcs(struct intel_panel *panel) +{ + struct intel_connector *connector = + container_of(panel, struct intel_connector, panel); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI && + intel_dsi_dcs_init_backlight_funcs(connector) == 0) + return; + + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { + panel->backlight.pwm_funcs = &bxt_pwm_funcs; + } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) { + panel->backlight.pwm_funcs = &cnp_pwm_funcs; + } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) { + if (HAS_PCH_LPT(dev_priv)) + panel->backlight.pwm_funcs = &lpt_pwm_funcs; + else + panel->backlight.pwm_funcs = &spt_pwm_funcs; + } else if (HAS_PCH_SPLIT(dev_priv)) { + panel->backlight.pwm_funcs = &pch_pwm_funcs; + } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { + panel->backlight.pwm_funcs = &ext_pwm_funcs; + } else { + panel->backlight.pwm_funcs = &vlv_pwm_funcs; + } + } else if (DISPLAY_VER(dev_priv) == 4) { + panel->backlight.pwm_funcs = &i965_pwm_funcs; + } else { + panel->backlight.pwm_funcs = &i9xx_pwm_funcs; + } + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP && + intel_dp_aux_init_backlight_funcs(connector) == 0) + return; + + /* We're using a standard PWM backlight interface */ + panel->backlight.funcs = &pwm_bl_funcs; +} diff --git a/drivers/gpu/drm/i915/display/intel_backlight.h b/drivers/gpu/drm/i915/display/intel_backlight.h new file mode 100644 index 0000000000000..282020cb47d5b --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_backlight.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_BACKLIGHT_H__ +#define __INTEL_BACKLIGHT_H__ + +#include + +struct drm_connector; +struct drm_connector_state; +struct intel_atomic_state; +struct intel_connector; +struct intel_crtc_state; +struct intel_encoder; +struct intel_panel; +enum pipe; + +void intel_panel_init_backlight_funcs(struct intel_panel *panel); +void intel_panel_destroy_backlight(struct intel_panel *panel); +void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, + u32 level, u32 max); +int intel_panel_setup_backlight(struct drm_connector *connector, + enum pipe pipe); +void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); +void intel_panel_update_backlight(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); +void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state); +void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level); +u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level); +u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level); +u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val); + +#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +int intel_backlight_device_register(struct intel_connector *connector); +void intel_backlight_device_unregister(struct intel_connector *connector); +#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +static inline int intel_backlight_device_register(struct intel_connector *connector) +{ + return 0; +} +static inline void intel_backlight_device_unregister(struct intel_connector *connector) +{ +} +#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + +#endif /* __INTEL_BACKLIGHT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 9bed1ccecea0d..4f49d782eca23 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -29,13 +29,13 @@ #include #include -#include "display/intel_panel.h" - #include "i915_drv.h" +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_display_debugfs.h" #include "intel_display_types.h" #include "intel_hdcp.h" +#include "intel_panel.h" int intel_connector_init(struct intel_connector *connector) { diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f61901e26409e..68489c7298302 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -29,6 +29,7 @@ #include "i915_drv.h" #include "intel_audio.h" +#include "intel_backlight.h" #include "intel_combo_phy.h" #include "intel_connector.h" #include "intel_crtc.h" @@ -49,7 +50,6 @@ #include "intel_hdmi.h" #include "intel_hotplug.h" #include "intel_lspcon.h" -#include "intel_panel.h" #include "intel_pps.h" #include "intel_psr.h" #include "intel_snps_phy.h" diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 631cf7d4323c8..f87e4d510ea5e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -45,6 +45,7 @@ #include "i915_drv.h" #include "intel_atomic.h" #include "intel_audio.h" +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_ddi.h" #include "intel_de.h" diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index e7b90863aa43d..0a77f0e48aa11 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -34,10 +34,10 @@ * for some reason. */ +#include "intel_backlight.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux_backlight.h" -#include "intel_panel.h" /* TODO: * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index e0381b0fce914..8f5741ebd58dd 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -40,6 +40,7 @@ #include "i915_drv.h" #include "intel_atomic.h" +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index f7f49b69830fa..aad5c1cd3898e 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -30,10 +30,9 @@ #include #include -#include "display/intel_panel.h" - #include "i915_drv.h" #include "intel_acpi.h" +#include "intel_backlight.h" #include "intel_display_types.h" #include "intel_opregion.h" diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 7d7a60b4d2de7..ad54767440c15 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -28,17 +28,13 @@ * Chris Wilson */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include -#include #include +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" -#include "intel_dp_aux_backlight.h" -#include "intel_dsi_dcs_backlight.h" #include "intel_panel.h" void @@ -456,1767 +452,6 @@ int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state, return 0; } -/** - * scale - scale values from one range to another - * @source_val: value in range [@source_min..@source_max] - * @source_min: minimum legal value for @source_val - * @source_max: maximum legal value for @source_val - * @target_min: corresponding target value for @source_min - * @target_max: corresponding target value for @source_max - * - * Return @source_val in range [@source_min..@source_max] scaled to range - * [@target_min..@target_max]. - */ -static u32 scale(u32 source_val, - u32 source_min, u32 source_max, - u32 target_min, u32 target_max) -{ - u64 target_val; - - WARN_ON(source_min > source_max); - WARN_ON(target_min > target_max); - - /* defensive */ - source_val = clamp(source_val, source_min, source_max); - - /* avoid overflows */ - target_val = mul_u32_u32(source_val - source_min, - target_max - target_min); - target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min); - target_val += target_min; - - return target_val; -} - -/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result - * to [hw_min..hw_max]. */ -static u32 clamp_user_to_hw(struct intel_connector *connector, - u32 user_level, u32 user_max) -{ - struct intel_panel *panel = &connector->panel; - u32 hw_level; - - hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); - hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); - - return hw_level; -} - -/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ -static u32 scale_hw_to_user(struct intel_connector *connector, - u32 hw_level, u32 user_max) -{ - struct intel_panel *panel = &connector->panel; - - return scale(hw_level, panel->backlight.min, panel->backlight.max, - 0, user_max); -} - -u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); - - if (dev_priv->params.invert_brightness < 0) - return val; - - if (dev_priv->params.invert_brightness > 0 || - dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { - return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; - } - - return val; -} - -void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *i915 = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val); - panel->backlight.pwm_funcs->set(conn_state, val); -} - -u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - drm_WARN_ON_ONCE(&dev_priv->drm, - panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); - - val = scale(val, panel->backlight.min, panel->backlight.max, - panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); - - return intel_panel_invert_pwm_level(connector, val); -} - -u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - drm_WARN_ON_ONCE(&dev_priv->drm, - panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); - - if (dev_priv->params.invert_brightness > 0 || - (dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)) - val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min); - - return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max, - panel->backlight.min, panel->backlight.max); -} - -static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; -} - -static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; -} - -static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 val; - - val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; - if (DISPLAY_VER(dev_priv) < 4) - val >>= 1; - - if (panel->backlight.combination_mode) { - u8 lbpc; - - pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc); - val *= lbpc; - } - - return val; -} - -static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) - return 0; - - return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; -} - -static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - return intel_de_read(dev_priv, - BXT_BLC_PWM_DUTY(panel->backlight.controller)); -} - -static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct intel_panel *panel = &connector->panel; - struct pwm_state state; - - pwm_get_state(panel->backlight.pwm, &state); - return pwm_get_relative_duty_cycle(&state, 100); -} - -static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; - intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level); -} - -static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - u32 tmp; - - tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level); -} - -static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 tmp, mask; - - drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); - - if (panel->backlight.combination_mode) { - u8 lbpc; - - lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1; - level /= lbpc; - pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); - } - - if (DISPLAY_VER(dev_priv) == 4) { - mask = BACKLIGHT_DUTY_CYCLE_MASK; - } else { - level <<= 1; - mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; - } - - tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask; - intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level); -} - -static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; - u32 tmp; - - tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; - intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level); -} - -static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - intel_de_write(dev_priv, - BXT_BLC_PWM_DUTY(panel->backlight.controller), level); -} - -static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; - - pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -} - -static void -intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *i915 = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level); - - panel->backlight.funcs->set(conn_state, level); -} - -/* set backlight brightness to level in range [0..max], assuming hw min is - * respected. - */ -void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, - u32 user_level, u32 user_max) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 hw_level; - - /* - * Lack of crtc may occur during driver init because - * connection_mutex isn't held across the entire backlight - * setup + modeset readout, and the BIOS can issue the - * requests at any time. - */ - if (!panel->backlight.present || !conn_state->crtc) - return; - - mutex_lock(&dev_priv->backlight_lock); - - drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); - - hw_level = clamp_user_to_hw(connector, user_level, user_max); - panel->backlight.level = hw_level; - - if (panel->backlight.device) - panel->backlight.device->props.brightness = - scale_hw_to_user(connector, - panel->backlight.level, - panel->backlight.device->props.max_brightness); - - if (panel->backlight.enabled) - intel_panel_actually_set_backlight(conn_state, hw_level); - - mutex_unlock(&dev_priv->backlight_lock); -} - -static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, level); - - /* - * Although we don't support or enable CPU PWM with LPT/SPT based - * systems, it may have been enabled prior to loading the - * driver. Disable to avoid warnings on LCPLL disable. - * - * This needs rework if we need to add support for CPU PWM on PCH split - * platforms. - */ - tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); - if (tmp & BLM_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, - "cpu backlight was enabled, disabling\n"); - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, - tmp & ~BLM_PWM_ENABLE); - } - - tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); -} - -static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, val); - - tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); - - tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); -} - -static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - intel_panel_set_pwm_level(old_conn_state, val); -} - -static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev); - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, val); - - tmp = intel_de_read(dev_priv, BLC_PWM_CTL2); - intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); -} - -static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe; - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, val); - - tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); - intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), - tmp & ~BLM_PWM_ENABLE); -} - -static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, val); - - tmp = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - tmp & ~BXT_BLC_PWM_ENABLE); - - if (panel->backlight.controller == 1) { - val = intel_de_read(dev_priv, UTIL_PIN_CTL); - val &= ~UTIL_PIN_ENABLE; - intel_de_write(dev_priv, UTIL_PIN_CTL, val); - } -} - -static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 tmp; - - intel_panel_set_pwm_level(old_conn_state, val); - - tmp = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - tmp & ~BXT_BLC_PWM_ENABLE); -} - -static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct intel_panel *panel = &connector->panel; - - panel->backlight.pwm_state.enabled = false; - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -} - -void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state) -{ - struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - if (!panel->backlight.present) - return; - - /* - * Do not disable backlight on the vga_switcheroo path. When switching - * away from i915, the other client may depend on i915 to handle the - * backlight. This will leave the backlight on unnecessarily when - * another client is not activated. - */ - if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) { - drm_dbg_kms(&dev_priv->drm, - "Skipping backlight disable on vga switch\n"); - return; - } - - mutex_lock(&dev_priv->backlight_lock); - - if (panel->backlight.device) - panel->backlight.device->props.power = FB_BLANK_POWERDOWN; - panel->backlight.enabled = false; - panel->backlight.funcs->disable(old_conn_state, 0); - - mutex_unlock(&dev_priv->backlight_lock); -} - -static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 pch_ctl1, pch_ctl2, schicken; - - pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); - pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); - } - - if (HAS_PCH_LPT(dev_priv)) { - schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2); - if (panel->backlight.alternate_pwm_increment) - schicken |= LPT_PWM_GRANULARITY; - else - schicken &= ~LPT_PWM_GRANULARITY; - intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken); - } else { - schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1); - if (panel->backlight.alternate_pwm_increment) - schicken |= SPT_PWM_GRANULARITY; - else - schicken &= ~SPT_PWM_GRANULARITY; - intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken); - } - - pch_ctl2 = panel->backlight.pwm_level_max << 16; - intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); - - pch_ctl1 = 0; - if (panel->backlight.active_low_pwm) - pch_ctl1 |= BLM_PCH_POLARITY; - - /* After LPT, override is the default. */ - if (HAS_PCH_LPT(dev_priv)) - pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; - - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); - intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, - pch_ctl1 | BLM_PCH_PWM_ENABLE); - - /* This won't stick until the above enable. */ - intel_panel_set_pwm_level(conn_state, level); -} - -static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - u32 cpu_ctl2, pch_ctl1, pch_ctl2; - - cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); - if (cpu_ctl2 & BLM_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n"); - cpu_ctl2 &= ~BLM_PWM_ENABLE; - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); - } - - pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n"); - pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); - } - - if (cpu_transcoder == TRANSCODER_EDP) - cpu_ctl2 = BLM_TRANSCODER_EDP; - else - cpu_ctl2 = BLM_PIPE(cpu_transcoder); - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2); - intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2); - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); - - /* This won't stick until the above enable. */ - intel_panel_set_pwm_level(conn_state, level); - - pch_ctl2 = panel->backlight.pwm_level_max << 16; - intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2); - - pch_ctl1 = 0; - if (panel->backlight.active_low_pwm) - pch_ctl1 |= BLM_PCH_POLARITY; - - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1); - intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1); - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, - pch_ctl1 | BLM_PCH_PWM_ENABLE); -} - -static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 ctl, freq; - - ctl = intel_de_read(dev_priv, BLC_PWM_CTL); - if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { - drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); - intel_de_write(dev_priv, BLC_PWM_CTL, 0); - } - - freq = panel->backlight.pwm_level_max; - if (panel->backlight.combination_mode) - freq /= 0xff; - - ctl = freq << 17; - if (panel->backlight.combination_mode) - ctl |= BLM_LEGACY_MODE; - if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm) - ctl |= BLM_POLARITY_PNV; - - intel_de_write(dev_priv, BLC_PWM_CTL, ctl); - intel_de_posting_read(dev_priv, BLC_PWM_CTL); - - /* XXX: combine this into above write? */ - intel_panel_set_pwm_level(conn_state, level); - - /* - * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is - * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 - * that has backlight. - */ - if (DISPLAY_VER(dev_priv) == 2) - intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); -} - -static void i965_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe; - u32 ctl, ctl2, freq; - - ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); - if (ctl2 & BLM_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); - ctl2 &= ~BLM_PWM_ENABLE; - intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); - } - - freq = panel->backlight.pwm_level_max; - if (panel->backlight.combination_mode) - freq /= 0xff; - - ctl = freq << 16; - intel_de_write(dev_priv, BLC_PWM_CTL, ctl); - - ctl2 = BLM_PIPE(pipe); - if (panel->backlight.combination_mode) - ctl2 |= BLM_COMBINATION_MODE; - if (panel->backlight.active_low_pwm) - ctl2 |= BLM_POLARITY_I965; - intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2); - intel_de_posting_read(dev_priv, BLC_PWM_CTL2); - intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); - - intel_panel_set_pwm_level(conn_state, level); -} - -static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - u32 ctl, ctl2; - - ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); - if (ctl2 & BLM_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); - ctl2 &= ~BLM_PWM_ENABLE; - intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); - } - - ctl = panel->backlight.pwm_level_max << 16; - intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl); - - /* XXX: combine this into above write? */ - intel_panel_set_pwm_level(conn_state, level); - - ctl2 = 0; - if (panel->backlight.active_low_pwm) - ctl2 |= BLM_POLARITY_I965; - intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2); - intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); - intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), - ctl2 | BLM_PWM_ENABLE); -} - -static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - u32 pwm_ctl, val; - - /* Controller 1 uses the utility pin. */ - if (panel->backlight.controller == 1) { - val = intel_de_read(dev_priv, UTIL_PIN_CTL); - if (val & UTIL_PIN_ENABLE) { - drm_dbg_kms(&dev_priv->drm, - "util pin already enabled\n"); - val &= ~UTIL_PIN_ENABLE; - intel_de_write(dev_priv, UTIL_PIN_CTL, val); - } - - val = 0; - if (panel->backlight.util_pin_active_low) - val |= UTIL_PIN_POLARITY; - intel_de_write(dev_priv, UTIL_PIN_CTL, - val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); - } - - pwm_ctl = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - if (pwm_ctl & BXT_BLC_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); - pwm_ctl &= ~BXT_BLC_PWM_ENABLE; - intel_de_write(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl); - } - - intel_de_write(dev_priv, - BXT_BLC_PWM_FREQ(panel->backlight.controller), - panel->backlight.pwm_level_max); - - intel_panel_set_pwm_level(conn_state, level); - - pwm_ctl = 0; - if (panel->backlight.active_low_pwm) - pwm_ctl |= BXT_BLC_PWM_POLARITY; - - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl); - intel_de_posting_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl | BXT_BLC_PWM_ENABLE); -} - -static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 pwm_ctl; - - pwm_ctl = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - if (pwm_ctl & BXT_BLC_PWM_ENABLE) { - drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n"); - pwm_ctl &= ~BXT_BLC_PWM_ENABLE; - intel_de_write(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl); - } - - intel_de_write(dev_priv, - BXT_BLC_PWM_FREQ(panel->backlight.controller), - panel->backlight.pwm_level_max); - - intel_panel_set_pwm_level(conn_state, level); - - pwm_ctl = 0; - if (panel->backlight.active_low_pwm) - pwm_ctl |= BXT_BLC_PWM_POLARITY; - - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl); - intel_de_posting_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller), - pwm_ctl | BXT_BLC_PWM_ENABLE); -} - -static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct intel_panel *panel = &connector->panel; - - pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); - panel->backlight.pwm_state.enabled = true; - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -} - -static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct intel_panel *panel = &connector->panel; - - WARN_ON(panel->backlight.max == 0); - - if (panel->backlight.level <= panel->backlight.min) { - panel->backlight.level = panel->backlight.max; - if (panel->backlight.device) - panel->backlight.device->props.brightness = - scale_hw_to_user(connector, - panel->backlight.level, - panel->backlight.device->props.max_brightness); - } - - panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level); - panel->backlight.enabled = true; - if (panel->backlight.device) - panel->backlight.device->props.power = FB_BLANK_UNBLANK; -} - -void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - - if (!panel->backlight.present) - return; - - drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe)); - - mutex_lock(&dev_priv->backlight_lock); - - __intel_panel_enable_backlight(crtc_state, conn_state); - - mutex_unlock(&dev_priv->backlight_lock); -} - -#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) -static u32 intel_panel_get_backlight(struct intel_connector *connector) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 val = 0; - - mutex_lock(&dev_priv->backlight_lock); - - if (panel->backlight.enabled) - val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector)); - - mutex_unlock(&dev_priv->backlight_lock); - - drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val); - return val; -} - -/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ -static u32 scale_user_to_hw(struct intel_connector *connector, - u32 user_level, u32 user_max) -{ - struct intel_panel *panel = &connector->panel; - - return scale(user_level, 0, user_max, - panel->backlight.min, panel->backlight.max); -} - -/* set backlight brightness to level in range [0..max], scaling wrt hw min */ -static void intel_panel_set_backlight(const struct drm_connector_state *conn_state, - u32 user_level, u32 user_max) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 hw_level; - - if (!panel->backlight.present) - return; - - mutex_lock(&dev_priv->backlight_lock); - - drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0); - - hw_level = scale_user_to_hw(connector, user_level, user_max); - panel->backlight.level = hw_level; - - if (panel->backlight.enabled) - intel_panel_actually_set_backlight(conn_state, hw_level); - - mutex_unlock(&dev_priv->backlight_lock); -} - -static int intel_backlight_device_update_status(struct backlight_device *bd) -{ - struct intel_connector *connector = bl_get_data(bd); - struct intel_panel *panel = &connector->panel; - struct drm_device *dev = connector->base.dev; - - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", - bd->props.brightness, bd->props.max_brightness); - intel_panel_set_backlight(connector->base.state, bd->props.brightness, - bd->props.max_brightness); - - /* - * Allow flipping bl_power as a sub-state of enabled. Sadly the - * backlight class device does not make it easy to to differentiate - * between callbacks for brightness and bl_power, so our backlight_power - * callback needs to take this into account. - */ - if (panel->backlight.enabled) { - if (panel->backlight.power) { - bool enable = bd->props.power == FB_BLANK_UNBLANK && - bd->props.brightness != 0; - panel->backlight.power(connector, enable); - } - } else { - bd->props.power = FB_BLANK_POWERDOWN; - } - - drm_modeset_unlock(&dev->mode_config.connection_mutex); - return 0; -} - -static int intel_backlight_device_get_brightness(struct backlight_device *bd) -{ - struct intel_connector *connector = bl_get_data(bd); - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - intel_wakeref_t wakeref; - int ret = 0; - - with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) { - u32 hw_level; - - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - - hw_level = intel_panel_get_backlight(connector); - ret = scale_hw_to_user(connector, - hw_level, bd->props.max_brightness); - - drm_modeset_unlock(&dev->mode_config.connection_mutex); - } - - return ret; -} - -static const struct backlight_ops intel_backlight_device_ops = { - .update_status = intel_backlight_device_update_status, - .get_brightness = intel_backlight_device_get_brightness, -}; - -int intel_backlight_device_register(struct intel_connector *connector) -{ - struct drm_i915_private *i915 = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - struct backlight_properties props; - struct backlight_device *bd; - const char *name; - int ret = 0; - - if (WARN_ON(panel->backlight.device)) - return -ENODEV; - - if (!panel->backlight.present) - return 0; - - WARN_ON(panel->backlight.max == 0); - - memset(&props, 0, sizeof(props)); - props.type = BACKLIGHT_RAW; - - /* - * Note: Everything should work even if the backlight device max - * presented to the userspace is arbitrarily chosen. - */ - props.max_brightness = panel->backlight.max; - props.brightness = scale_hw_to_user(connector, - panel->backlight.level, - props.max_brightness); - - if (panel->backlight.enabled) - props.power = FB_BLANK_UNBLANK; - else - props.power = FB_BLANK_POWERDOWN; - - name = kstrdup("intel_backlight", GFP_KERNEL); - if (!name) - return -ENOMEM; - - bd = backlight_device_register(name, connector->base.kdev, connector, - &intel_backlight_device_ops, &props); - - /* - * Using the same name independent of the drm device or connector - * prevents registration of multiple backlight devices in the - * driver. However, we need to use the default name for backward - * compatibility. Use unique names for subsequent backlight devices as a - * fallback when the default name already exists. - */ - if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) { - kfree(name); - name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", - i915->drm.primary->index, connector->base.name); - if (!name) - return -ENOMEM; - - bd = backlight_device_register(name, connector->base.kdev, connector, - &intel_backlight_device_ops, &props); - } - - if (IS_ERR(bd)) { - drm_err(&i915->drm, - "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n", - connector->base.base.id, connector->base.name, name, PTR_ERR(bd)); - ret = PTR_ERR(bd); - goto out; - } - - panel->backlight.device = bd; - - drm_dbg_kms(&i915->drm, - "[CONNECTOR:%d:%s] backlight device %s registered\n", - connector->base.base.id, connector->base.name, name); - -out: - kfree(name); - - return ret; -} - -void intel_backlight_device_unregister(struct intel_connector *connector) -{ - struct intel_panel *panel = &connector->panel; - - if (panel->backlight.device) { - backlight_device_unregister(panel->backlight.device); - panel->backlight.device = NULL; - } -} -#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ - -/* - * CNP: PWM clock frequency is 19.2 MHz or 24 MHz. - * PWM increment = 1 - */ -static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), - pwm_freq_hz); -} - -/* - * BXT: PWM clock frequency = 19.2 MHz. - */ -static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz); -} - -/* - * SPT: This value represents the period of the PWM stream in clock periods - * multiplied by 16 (default increment) or 128 (alternate increment selected in - * SCHICKEN_1 bit 0). PWM clock is 24 MHz. - */ -static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct intel_panel *panel = &connector->panel; - u32 mul; - - if (panel->backlight.alternate_pwm_increment) - mul = 128; - else - mul = 16; - - return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul); -} - -/* - * LPT: This value represents the period of the PWM stream in clock periods - * multiplied by 128 (default increment) or 16 (alternate increment, selected in - * LPT SOUTH_CHICKEN2 register bit 5). - */ -static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 mul, clock; - - if (panel->backlight.alternate_pwm_increment) - mul = 16; - else - mul = 128; - - if (HAS_PCH_LPT_H(dev_priv)) - clock = MHz(135); /* LPT:H */ - else - clock = MHz(24); /* LPT:LP */ - - return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); -} - -/* - * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH - * display raw clocks multiplied by 128. - */ -static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq), - pwm_freq_hz * 128); -} - -/* - * Gen2: This field determines the number of time base events (display core - * clock frequency/32) in total for a complete cycle of modulated backlight - * control. - * - * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) - * divided by 32. - */ -static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - int clock; - - if (IS_PINEVIEW(dev_priv)) - clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); - else - clock = KHz(dev_priv->cdclk.hw.cdclk); - - return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32); -} - -/* - * Gen4: This value represents the period of the PWM stream in display core - * clocks ([DevCTG] HRAW clocks) multiplied by 128. - * - */ -static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - int clock; - - if (IS_G4X(dev_priv)) - clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); - else - clock = KHz(dev_priv->cdclk.hw.cdclk); - - return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128); -} - -/* - * VLV: This value represents the period of the PWM stream in display core - * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks - * multiplied by 16. CHV uses a 19.2MHz S0IX clock. - */ -static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - int mul, clock; - - if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) { - if (IS_CHERRYVIEW(dev_priv)) - clock = KHz(19200); - else - clock = MHz(25); - mul = 16; - } else { - clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq); - mul = 128; - } - - return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); -} - -static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv) -{ - u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; - - if (pwm_freq_hz) { - drm_dbg_kms(&dev_priv->drm, - "VBT defined backlight frequency %u Hz\n", - pwm_freq_hz); - } else { - pwm_freq_hz = 200; - drm_dbg_kms(&dev_priv->drm, - "default backlight frequency %u Hz\n", - pwm_freq_hz); - } - - return pwm_freq_hz; -} - -static u32 get_backlight_max_vbt(struct intel_connector *connector) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv); - u32 pwm; - - if (!panel->backlight.pwm_funcs->hz_to_pwm) { - drm_dbg_kms(&dev_priv->drm, - "backlight frequency conversion not supported\n"); - return 0; - } - - pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz); - if (!pwm) { - drm_dbg_kms(&dev_priv->drm, - "backlight frequency conversion failed\n"); - return 0; - } - - return pwm; -} - -/* - * Note: The setup hooks can't assume pipe is set! - */ -static u32 get_backlight_min_vbt(struct intel_connector *connector) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - int min; - - drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0); - - /* - * XXX: If the vbt value is 255, it makes min equal to max, which leads - * to problems. There are such machines out there. Either our - * interpretation is wrong or the vbt has bogus data. Or both. Safeguard - * against this by letting the minimum be at most (arbitrarily chosen) - * 25% of the max. - */ - min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); - if (min != dev_priv->vbt.backlight.min_brightness) { - drm_dbg_kms(&dev_priv->drm, - "clamping VBT min backlight %d/255 to %d/255\n", - dev_priv->vbt.backlight.min_brightness, min); - } - - /* vbt value is a coefficient in range [0..255] */ - return scale(min, 0, 255, 0, panel->backlight.pwm_level_max); -} - -static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; - bool alt, cpu_mode; - - if (HAS_PCH_LPT(dev_priv)) - alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY; - else - alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY; - panel->backlight.alternate_pwm_increment = alt; - - pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; - - pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); - panel->backlight.pwm_level_max = pch_ctl2 >> 16; - - cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE; - - cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) && - !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) && - (cpu_ctl2 & BLM_PWM_ENABLE); - - if (cpu_mode) { - val = pch_get_backlight(connector, unused); - - drm_dbg_kms(&dev_priv->drm, - "CPU backlight register was enabled, switching to PCH override\n"); - - /* Write converted CPU PWM value to PCH override register */ - lpt_set_backlight(connector->base.state, val); - intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, - pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE); - - intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, - cpu_ctl2 & ~BLM_PWM_ENABLE); - } - - return 0; -} - -static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 cpu_ctl2, pch_ctl1, pch_ctl2; - - pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1); - panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; - - pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2); - panel->backlight.pwm_level_max = pch_ctl2 >> 16; - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2); - panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && - (pch_ctl1 & BLM_PCH_PWM_ENABLE); - - return 0; -} - -static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 ctl, val; - - ctl = intel_de_read(dev_priv, BLC_PWM_CTL); - - if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) - panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; - - if (IS_PINEVIEW(dev_priv)) - panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; - - panel->backlight.pwm_level_max = ctl >> 17; - - if (!panel->backlight.pwm_level_max) { - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - panel->backlight.pwm_level_max >>= 1; - } - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - if (panel->backlight.combination_mode) - panel->backlight.pwm_level_max *= 0xff; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - val = i9xx_get_backlight(connector, unused); - val = intel_panel_invert_pwm_level(connector, val); - val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max); - - panel->backlight.pwm_enabled = val != 0; - - return 0; -} - -static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 ctl, ctl2; - - ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2); - panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; - panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; - - ctl = intel_de_read(dev_priv, BLC_PWM_CTL); - panel->backlight.pwm_level_max = ctl >> 16; - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - if (panel->backlight.combination_mode) - panel->backlight.pwm_level_max *= 0xff; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; - - return 0; -} - -static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 ctl, ctl2; - - if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B)) - return -ENODEV; - - ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe)); - panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; - - ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)); - panel->backlight.pwm_level_max = ctl >> 16; - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE; - - return 0; -} - -static int -bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 pwm_ctl, val; - - panel->backlight.controller = dev_priv->vbt.backlight.controller; - - pwm_ctl = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - - /* Controller 1 uses the utility pin. */ - if (panel->backlight.controller == 1) { - val = intel_de_read(dev_priv, UTIL_PIN_CTL); - panel->backlight.util_pin_active_low = - val & UTIL_PIN_POLARITY; - } - - panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; - panel->backlight.pwm_level_max = - intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; - - return 0; -} - -static int -cnp_setup_backlight(struct intel_connector *connector, enum pipe unused) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - u32 pwm_ctl; - - /* - * CNP has the BXT implementation of backlight, but with only one - * controller. TODO: ICP has multiple controllers but we only use - * controller 0 for now. - */ - panel->backlight.controller = 0; - - pwm_ctl = intel_de_read(dev_priv, - BXT_BLC_PWM_CTL(panel->backlight.controller)); - - panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; - panel->backlight.pwm_level_max = - intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller)); - - if (!panel->backlight.pwm_level_max) - panel->backlight.pwm_level_max = get_backlight_max_vbt(connector); - - if (!panel->backlight.pwm_level_max) - return -ENODEV; - - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE; - - return 0; -} - -static int ext_pwm_setup_backlight(struct intel_connector *connector, - enum pipe pipe) -{ - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_panel *panel = &connector->panel; - const char *desc; - u32 level; - - /* Get the right PWM chip for DSI backlight according to VBT */ - if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { - panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight"); - desc = "PMIC"; - } else { - panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight"); - desc = "SoC"; - } - - if (IS_ERR(panel->backlight.pwm)) { - drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n", - desc); - panel->backlight.pwm = NULL; - return -ENODEV; - } - - panel->backlight.pwm_level_max = 100; /* 100% */ - panel->backlight.pwm_level_min = get_backlight_min_vbt(connector); - - if (pwm_is_enabled(panel->backlight.pwm)) { - /* PWM is already enabled, use existing settings */ - pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state); - - level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state, - 100); - level = intel_panel_invert_pwm_level(connector, level); - panel->backlight.pwm_enabled = true; - - drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n", - NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period, - get_vbt_pwm_freq(dev_priv), level); - } else { - /* Set period from VBT frequency, leave other settings at 0. */ - panel->backlight.pwm_state.period = - NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv); - } - - drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n", - desc); - return 0; -} - -static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct intel_panel *panel = &connector->panel; - - panel->backlight.pwm_funcs->set(conn_state, - intel_panel_invert_pwm_level(connector, level)); -} - -static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe) -{ - struct intel_panel *panel = &connector->panel; - - return intel_panel_invert_pwm_level(connector, - panel->backlight.pwm_funcs->get(connector, pipe)); -} - -static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct intel_panel *panel = &connector->panel; - - panel->backlight.pwm_funcs->enable(crtc_state, conn_state, - intel_panel_invert_pwm_level(connector, level)); -} - -static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct intel_panel *panel = &connector->panel; - - panel->backlight.pwm_funcs->disable(conn_state, - intel_panel_invert_pwm_level(connector, level)); -} - -static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe) -{ - struct intel_panel *panel = &connector->panel; - int ret = panel->backlight.pwm_funcs->setup(connector, pipe); - - if (ret < 0) - return ret; - - panel->backlight.min = panel->backlight.pwm_level_min; - panel->backlight.max = panel->backlight.pwm_level_max; - panel->backlight.level = intel_pwm_get_backlight(connector, pipe); - panel->backlight.enabled = panel->backlight.pwm_enabled; - - return 0; -} - -void intel_panel_update_backlight(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_panel *panel = &connector->panel; - - if (!panel->backlight.present) - return; - - mutex_lock(&dev_priv->backlight_lock); - if (!panel->backlight.enabled) - __intel_panel_enable_backlight(crtc_state, conn_state); - - mutex_unlock(&dev_priv->backlight_lock); -} - -int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = to_i915(connector->dev); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_panel *panel = &intel_connector->panel; - int ret; - - if (!dev_priv->vbt.backlight.present) { - if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { - drm_dbg_kms(&dev_priv->drm, - "no backlight present per VBT, but present per quirk\n"); - } else { - drm_dbg_kms(&dev_priv->drm, - "no backlight present per VBT\n"); - return 0; - } - } - - /* ensure intel_panel has been initialized first */ - if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs)) - return -ENODEV; - - /* set level and max in panel struct */ - mutex_lock(&dev_priv->backlight_lock); - ret = panel->backlight.funcs->setup(intel_connector, pipe); - mutex_unlock(&dev_priv->backlight_lock); - - if (ret) { - drm_dbg_kms(&dev_priv->drm, - "failed to setup backlight for connector %s\n", - connector->name); - return ret; - } - - panel->backlight.present = true; - - drm_dbg_kms(&dev_priv->drm, - "Connector %s backlight initialized, %s, brightness %u/%u\n", - connector->name, - enableddisabled(panel->backlight.enabled), - panel->backlight.level, panel->backlight.max); - - return 0; -} - -static void intel_panel_destroy_backlight(struct intel_panel *panel) -{ - /* dispose of the pwm */ - if (panel->backlight.pwm) - pwm_put(panel->backlight.pwm); - - panel->backlight.present = false; -} - -static const struct intel_panel_bl_funcs bxt_pwm_funcs = { - .setup = bxt_setup_backlight, - .enable = bxt_enable_backlight, - .disable = bxt_disable_backlight, - .set = bxt_set_backlight, - .get = bxt_get_backlight, - .hz_to_pwm = bxt_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs cnp_pwm_funcs = { - .setup = cnp_setup_backlight, - .enable = cnp_enable_backlight, - .disable = cnp_disable_backlight, - .set = bxt_set_backlight, - .get = bxt_get_backlight, - .hz_to_pwm = cnp_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs lpt_pwm_funcs = { - .setup = lpt_setup_backlight, - .enable = lpt_enable_backlight, - .disable = lpt_disable_backlight, - .set = lpt_set_backlight, - .get = lpt_get_backlight, - .hz_to_pwm = lpt_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs spt_pwm_funcs = { - .setup = lpt_setup_backlight, - .enable = lpt_enable_backlight, - .disable = lpt_disable_backlight, - .set = lpt_set_backlight, - .get = lpt_get_backlight, - .hz_to_pwm = spt_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs pch_pwm_funcs = { - .setup = pch_setup_backlight, - .enable = pch_enable_backlight, - .disable = pch_disable_backlight, - .set = pch_set_backlight, - .get = pch_get_backlight, - .hz_to_pwm = pch_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs ext_pwm_funcs = { - .setup = ext_pwm_setup_backlight, - .enable = ext_pwm_enable_backlight, - .disable = ext_pwm_disable_backlight, - .set = ext_pwm_set_backlight, - .get = ext_pwm_get_backlight, -}; - -static const struct intel_panel_bl_funcs vlv_pwm_funcs = { - .setup = vlv_setup_backlight, - .enable = vlv_enable_backlight, - .disable = vlv_disable_backlight, - .set = vlv_set_backlight, - .get = vlv_get_backlight, - .hz_to_pwm = vlv_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs i965_pwm_funcs = { - .setup = i965_setup_backlight, - .enable = i965_enable_backlight, - .disable = i965_disable_backlight, - .set = i9xx_set_backlight, - .get = i9xx_get_backlight, - .hz_to_pwm = i965_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs i9xx_pwm_funcs = { - .setup = i9xx_setup_backlight, - .enable = i9xx_enable_backlight, - .disable = i9xx_disable_backlight, - .set = i9xx_set_backlight, - .get = i9xx_get_backlight, - .hz_to_pwm = i9xx_hz_to_pwm, -}; - -static const struct intel_panel_bl_funcs pwm_bl_funcs = { - .setup = intel_pwm_setup_backlight, - .enable = intel_pwm_enable_backlight, - .disable = intel_pwm_disable_backlight, - .set = intel_pwm_set_backlight, - .get = intel_pwm_get_backlight, -}; - -/* Set up chip specific backlight functions */ -static void -intel_panel_init_backlight_funcs(struct intel_panel *panel) -{ - struct intel_connector *connector = - container_of(panel, struct intel_connector, panel); - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI && - intel_dsi_dcs_init_backlight_funcs(connector) == 0) - return; - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - panel->backlight.pwm_funcs = &bxt_pwm_funcs; - } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) { - panel->backlight.pwm_funcs = &cnp_pwm_funcs; - } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) { - if (HAS_PCH_LPT(dev_priv)) - panel->backlight.pwm_funcs = &lpt_pwm_funcs; - else - panel->backlight.pwm_funcs = &spt_pwm_funcs; - } else if (HAS_PCH_SPLIT(dev_priv)) { - panel->backlight.pwm_funcs = &pch_pwm_funcs; - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { - panel->backlight.pwm_funcs = &ext_pwm_funcs; - } else { - panel->backlight.pwm_funcs = &vlv_pwm_funcs; - } - } else if (DISPLAY_VER(dev_priv) == 4) { - panel->backlight.pwm_funcs = &i965_pwm_funcs; - } else { - panel->backlight.pwm_funcs = &i9xx_pwm_funcs; - } - - if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP && - intel_dp_aux_init_backlight_funcs(connector) == 0) - return; - - /* We're using a standard PWM backlight interface */ - panel->backlight.funcs = &pwm_bl_funcs; -} - enum drm_connector_status intel_panel_detect(struct drm_connector *connector, bool force) { diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index 1d340f77bffc7..67dbb15026bf1 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -8,15 +8,13 @@ #include -#include "intel_display.h" - +enum drm_connector_status; struct drm_connector; struct drm_connector_state; struct drm_display_mode; +struct drm_i915_private; struct intel_connector; -struct intel_crtc; struct intel_crtc_state; -struct intel_encoder; struct intel_panel; int intel_panel_init(struct intel_panel *panel, @@ -31,17 +29,6 @@ int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); int intel_gmch_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); -void intel_panel_set_backlight_acpi(const struct drm_connector_state *conn_state, - u32 level, u32 max); -int intel_panel_setup_backlight(struct drm_connector *connector, - enum pipe pipe); -void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state); -void intel_panel_update_backlight(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state); -void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state); struct drm_display_mode * intel_panel_edid_downclock_mode(struct intel_connector *connector, const struct drm_display_mode *fixed_mode); @@ -49,22 +36,5 @@ struct drm_display_mode * intel_panel_edid_fixed_mode(struct intel_connector *connector); struct drm_display_mode * intel_panel_vbt_fixed_mode(struct intel_connector *connector); -void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level); -u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level); -u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level); -u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val); - -#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) -int intel_backlight_device_register(struct intel_connector *connector); -void intel_backlight_device_unregister(struct intel_connector *connector); -#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ -static inline int intel_backlight_device_register(struct intel_connector *connector) -{ - return 0; -} -static inline void intel_backlight_device_unregister(struct intel_connector *connector) -{ -} -#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ #endif /* __INTEL_PANEL_H__ */ diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 0ee4ff341e25d..b27738df447d0 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -32,6 +32,7 @@ #include "i915_drv.h" #include "intel_atomic.h" +#include "intel_backlight.h" #include "intel_connector.h" #include "intel_crtc.h" #include "intel_de.h" From 7828b5d0080a4621973ab5c680c4df0bc6d96437 Mon Sep 17 00:00:00 2001 From: Arun R Murthy Date: Mon, 8 Aug 2022 09:27:50 +0530 Subject: [PATCH 012/228] drm/i915/display: avoid warnings when registering dual panel backlight [ Upstream commit 868e8e5156a1f8d92ca83fdbac6fd52798650792 ] Commit 20f85ef89d94 ("drm/i915/backlight: use unique backlight device names") added support for multiple backlight devices on dual panel systems, but did so with error handling on -EEXIST from backlight_device_register(). Unfortunately, that triggered a warning in dmesg all the way down from sysfs_add_file_mode_ns() and sysfs_warn_dup(). Instead of optimistically always attempting to register with the default name ("intel_backlight", which we have to retain for backward compatibility), check if a backlight device with the name exists first, and, if so, use the card and connector based name. v2: reworked on top of the patch commit 20f85ef89d94 ("drm/i915/backlight: use unique backlight device names") v3: fixed the ref count leak(Jani N) Fixes: 20f85ef89d94 ("drm/i915/backlight: use unique backlight device names") Signed-off-by: Arun R Murthy Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220808035750.3111046-1-arun.r.murthy@intel.com (cherry picked from commit 4234ea30051200fc6016de10e4d58369e60b38f1) Signed-off-by: Rodrigo Vivi Signed-off-by: Sasha Levin --- .../gpu/drm/i915/display/intel_backlight.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 4b0086ee48519..60f91ac7d1427 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -966,26 +966,24 @@ int intel_backlight_device_register(struct intel_connector *connector) if (!name) return -ENOMEM; - bd = backlight_device_register(name, connector->base.kdev, connector, - &intel_backlight_device_ops, &props); - - /* - * Using the same name independent of the drm device or connector - * prevents registration of multiple backlight devices in the - * driver. However, we need to use the default name for backward - * compatibility. Use unique names for subsequent backlight devices as a - * fallback when the default name already exists. - */ - if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) { + bd = backlight_device_get_by_name(name); + if (bd) { + put_device(&bd->dev); + /* + * Using the same name independent of the drm device or connector + * prevents registration of multiple backlight devices in the + * driver. However, we need to use the default name for backward + * compatibility. Use unique names for subsequent backlight devices as a + * fallback when the default name already exists. + */ kfree(name); name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", i915->drm.primary->index, connector->base.name); if (!name) return -ENOMEM; - - bd = backlight_device_register(name, connector->base.kdev, connector, - &intel_backlight_device_ops, &props); } + bd = backlight_device_register(name, connector->base.kdev, connector, + &intel_backlight_device_ops, &props); if (IS_ERR(bd)) { drm_err(&i915->drm, From 59a711467e8d101ec77f3f9fb5c1d0189fbafd5c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 16 Jun 2022 17:05:59 -0500 Subject: [PATCH 013/228] ALSA: hda: intel-nhlt: remove use of __func__ in dev_dbg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6376ab02374822e1e8758a848ee736a182786a2e ] The module and function information can be added with 'modprobe foo dyndbg=+pmf' Suggested-by: Greg KH Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220616220559.136160-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/intel-nhlt.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index e2237239d922a..5e04fedaec49e 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -55,8 +55,8 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) /* find max number of channels based on format_configuration */ if (fmt_configs->fmt_count) { - dev_dbg(dev, "%s: found %d format definitions\n", - __func__, fmt_configs->fmt_count); + dev_dbg(dev, "found %d format definitions\n", + fmt_configs->fmt_count); for (i = 0; i < fmt_configs->fmt_count; i++) { struct wav_fmt_ext *fmt_ext; @@ -66,9 +66,9 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) if (fmt_ext->fmt.channels > max_ch) max_ch = fmt_ext->fmt.channels; } - dev_dbg(dev, "%s: max channels found %d\n", __func__, max_ch); + dev_dbg(dev, "max channels found %d\n", max_ch); } else { - dev_dbg(dev, "%s: No format information found\n", __func__); + dev_dbg(dev, "No format information found\n"); } if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) { @@ -95,17 +95,16 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) } if (dmic_geo > 0) { - dev_dbg(dev, "%s: Array with %d dmics\n", __func__, dmic_geo); + dev_dbg(dev, "Array with %d dmics\n", dmic_geo); } if (max_ch > dmic_geo) { - dev_dbg(dev, "%s: max channels %d exceed dmic number %d\n", - __func__, max_ch, dmic_geo); + dev_dbg(dev, "max channels %d exceed dmic number %d\n", + max_ch, dmic_geo); } } } - dev_dbg(dev, "%s: dmic number %d max_ch %d\n", - __func__, dmic_geo, max_ch); + dev_dbg(dev, "dmic number %d max_ch %d\n", dmic_geo, max_ch); return dmic_geo; } From 20b2d5be85e937be63d05fce718ab3a67851feb0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 23 Aug 2022 15:24:05 +0300 Subject: [PATCH 014/228] ALSA: hda: intel-nhlt: Correct the handling of fmt_config flexible array [ Upstream commit 2e6481a3f3ee6234ce577454e1d88aca55f51d47 ] The struct nhlt_format's fmt_config is a flexible array, it must not be used as normal array. When moving to the next nhlt_fmt_cfg we need to take into account the data behind the ->config.caps (indicated by ->config.size). Fixes: a864e8f159b13 ("ALSA: hda: intel-nhlt: verify config type") Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Jaska Uimonen Link: https://lore.kernel.org/r/20220823122405.18464-1-peter.ujfalusi@linux.intel.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/intel-nhlt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 5e04fedaec49e..8714891f50b0a 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -55,16 +55,22 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) /* find max number of channels based on format_configuration */ if (fmt_configs->fmt_count) { + struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config; + dev_dbg(dev, "found %d format definitions\n", fmt_configs->fmt_count); for (i = 0; i < fmt_configs->fmt_count; i++) { struct wav_fmt_ext *fmt_ext; - fmt_ext = &fmt_configs->fmt_config[i].fmt_ext; + fmt_ext = &fmt_cfg->fmt_ext; if (fmt_ext->fmt.channels > max_ch) max_ch = fmt_ext->fmt.channels; + + /* Move to the next nhlt_fmt_cfg */ + fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + + fmt_cfg->config.size); } dev_dbg(dev, "max channels found %d\n", max_ch); } else { From ee19bbed4b031f034c5ab6320782e357c5ac16e7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Aug 2022 10:03:21 +0300 Subject: [PATCH 015/228] wifi: cfg80211: debugfs: fix return type in ht40allow_map_read() [ Upstream commit d776763f48084926b5d9e25507a3ddb7c9243d5e ] The return type is supposed to be ssize_t, which is signed long, but "r" was declared as unsigned int. This means that on 64 bit systems we return positive values instead of negative error codes. Fixes: 80a3511d70e8 ("cfg80211: add debugfs HT40 allow map") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YutvOQeJm0UjLhwU@kili Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index aab43469a2f04..0878b162890af 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -65,9 +65,10 @@ static ssize_t ht40allow_map_read(struct file *file, { struct wiphy *wiphy = file->private_data; char *buf; - unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; + unsigned int offset = 0, buf_size = PAGE_SIZE, i; enum nl80211_band band; struct ieee80211_supported_band *sband; + ssize_t r; buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) From 5359524251d27d5fb50e425bac0108a134ed682c Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 25 Aug 2022 18:08:40 +0300 Subject: [PATCH 016/228] Revert "xhci: turn off port power in shutdown" [ Upstream commit 8531aa1659f7278d4f2ec7408cc000eaa8d85217 ] This reverts commit 83810f84ecf11dfc5a9414a8b762c3501b328185. Turning off port power in shutdown did cause issues such as a laptop not proprly powering off, and some specific usb devies failing to enumerate the subsequent boot after a warm reset. So revert this. Fixes: 83810f84ecf1 ("xhci: turn off port power in shutdown") Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20220825150840.132216-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-hub.c | 2 +- drivers/usb/host/xhci.c | 15 ++------------- drivers/usb/host/xhci.h | 2 -- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fc322a9526c8c..f65f1ba2b5929 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) * It will release and re-aquire the lock while calling ACPI * method. */ -void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, +static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, bool on, unsigned long *flags) __must_hold(&xhci->lock) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d76c10f9ad807..e3767651c9a9e 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -776,8 +776,6 @@ static void xhci_stop(struct usb_hcd *hcd) void xhci_shutdown(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - unsigned long flags; - int i; if (xhci->quirks & XHCI_SPURIOUS_REBOOT) usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev)); @@ -793,21 +791,12 @@ void xhci_shutdown(struct usb_hcd *hcd) del_timer_sync(&xhci->shared_hcd->rh_timer); } - spin_lock_irqsave(&xhci->lock, flags); + spin_lock_irq(&xhci->lock); xhci_halt(xhci); - - /* Power off USB2 ports*/ - for (i = 0; i < xhci->usb2_rhub.num_ports; i++) - xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags); - - /* Power off USB3 ports*/ - for (i = 0; i < xhci->usb3_rhub.num_ports; i++) - xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags); - /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); - spin_unlock_irqrestore(&xhci->lock, flags); + spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 101f1956a96ca..81e1bfdf83988 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2174,8 +2174,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd); -void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, - bool on, unsigned long *flags); void xhci_hc_died(struct xhci_hcd *xhci); From cc2b9170aa34e0e1ae54c8da52c5bb1dfb01b0c5 Mon Sep 17 00:00:00 2001 From: Casper Andersson Date: Thu, 25 Aug 2022 10:49:55 +0200 Subject: [PATCH 017/228] net: sparx5: fix handling uneven length packets in manual extraction [ Upstream commit 7498a457ecf7ff2c4d379360aa8f24566bb1543e ] Packets that are not of length divisible by 4 (e.g. 77, 78, 79) would have the checksum included up to next multiple of 4 (a 77 bytes packet would have 3 bytes of ethernet checksum included). The check for the value expects it in host (Little) endian. Fixes: f3cad2611a77 ("net: sparx5: add hostmode with phylink support") Signed-off-by: Casper Andersson Reviewed-by: Steen Hegelund Link: https://lore.kernel.org/r/20220825084955.684637-1-casper.casan@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/microchip/sparx5/sparx5_packet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c index 148d431fcde42..c460168131c26 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c @@ -107,6 +107,8 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap) /* This assumes STATUS_WORD_POS == 1, Status * just after last data */ + if (!byte_swap) + val = ntohl((__force __be32)val); byte_cnt -= (4 - XTR_VALID_BYTES(val)); eof_flag = true; break; From 8eeba7ef4d1dce814ba3ffda4cf516e68be5536f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 24 Aug 2022 19:39:51 -0700 Subject: [PATCH 018/228] net: smsc911x: Stop and start PHY during suspend and resume [ Upstream commit 3ce9f2bef75528936c78a7053301f5725f622f3a ] Commit 744d23c71af3 ("net: phy: Warn about incorrect mdio_bus_phy_resume() state") unveiled that the smsc911x driver was not properly stopping and restarting the PHY during suspend/resume. Correct that by indicating that the MAC is in charge of PHY PM operations and ensure that all MDIO bus activity is quiescent during suspend. Tested-by: Geert Uytterhoeven Tested-by: Marek Szyprowski Fixes: fba863b81604 ("net: phy: make PHY PM ops a no-op if MAC driver manages PHY PM") Fixes: 2aa70f864955 ("net: smsc911x: Quieten netif during suspend") Signed-off-by: Florian Fainelli Link: https://lore.kernel.org/r/20220825023951.3220-1-f.fainelli@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/smsc/smsc911x.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 592e191adbf7d..63b99dd8ca51c 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1037,6 +1037,8 @@ static int smsc911x_mii_probe(struct net_device *dev) return ret; } + /* Indicate that the MAC is responsible for managing PHY PM */ + phydev->mac_managed_pm = true; phy_attached_info(phydev); phy_set_max_speed(phydev, SPEED_100); @@ -2584,6 +2586,8 @@ static int smsc911x_suspend(struct device *dev) if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); + if (!device_may_wakeup(dev)) + phy_stop(ndev->phydev); } /* enable wake on LAN, energy detection and the external PME @@ -2625,6 +2629,8 @@ static int smsc911x_resume(struct device *dev) if (netif_running(ndev)) { netif_device_attach(ndev); netif_start_queue(ndev); + if (!device_may_wakeup(dev)) + phy_start(ndev->phydev); } return 0; From ca54b2bfaab385778e55a9fd33f6c31e7f743b48 Mon Sep 17 00:00:00 2001 From: Andrey Zhadchenko Date: Thu, 25 Aug 2022 05:03:26 +0300 Subject: [PATCH 019/228] openvswitch: fix memory leak at failed datapath creation [ Upstream commit a87406f4adee9c53b311d8a1ba2849c69e29a6d0 ] ovs_dp_cmd_new()->ovs_dp_change()->ovs_dp_set_upcall_portids() allocates array via kmalloc. If for some reason new_vport() fails during ovs_dp_cmd_new() dp->upcall_portids must be freed. Add missing kfree. Kmemleak example: unreferenced object 0xffff88800c382500 (size 64): comm "dump_state", pid 323, jiffies 4294955418 (age 104.347s) hex dump (first 32 bytes): 5e c2 79 e4 1f 7a 38 c7 09 21 38 0c 80 88 ff ff ^.y..z8..!8..... 03 00 00 00 0a 00 00 00 14 00 00 00 28 00 00 00 ............(... backtrace: [<0000000071bebc9f>] ovs_dp_set_upcall_portids+0x38/0xa0 [<000000000187d8bd>] ovs_dp_change+0x63/0xe0 [<000000002397e446>] ovs_dp_cmd_new+0x1f0/0x380 [<00000000aa06f36e>] genl_family_rcv_msg_doit+0xea/0x150 [<000000008f583bc4>] genl_rcv_msg+0xdc/0x1e0 [<00000000fa10e377>] netlink_rcv_skb+0x50/0x100 [<000000004959cece>] genl_rcv+0x24/0x40 [<000000004699ac7f>] netlink_unicast+0x23e/0x360 [<00000000c153573e>] netlink_sendmsg+0x24e/0x4b0 [<000000006f4aa380>] sock_sendmsg+0x62/0x70 [<00000000d0068654>] ____sys_sendmsg+0x230/0x270 [<0000000012dacf7d>] ___sys_sendmsg+0x88/0xd0 [<0000000011776020>] __sys_sendmsg+0x59/0xa0 [<000000002e8f2dc1>] do_syscall_64+0x3b/0x90 [<000000003243e7cb>] entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: b83d23a2a38b ("openvswitch: Introduce per-cpu upcall dispatch") Acked-by: Aaron Conole Signed-off-by: Andrey Zhadchenko Link: https://lore.kernel.org/r/20220825020326.664073-1-andrey.zhadchenko@virtuozzo.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/openvswitch/datapath.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 67ad08320886b..5e2c83cb7b129 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1801,7 +1801,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_dp_reset_user_features(skb, info); } - goto err_unlock_and_destroy_meters; + goto err_destroy_portids; } err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, @@ -1816,6 +1816,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_notify(&dp_datapath_genl_family, reply, info); return 0; +err_destroy_portids: + kfree(rcu_dereference_raw(dp->upcall_portids)); err_unlock_and_destroy_meters: ovs_unlock(); ovs_meters_exit(dp); From d6ec2f711c945ee969be5709aa23e40ae4c57368 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 25 Aug 2022 13:36:44 +0200 Subject: [PATCH 020/228] net: dsa: xrs700x: Use irqsave variant for u64 stats update [ Upstream commit 3f8ae9fe0409698799e173f698b714f34570b64b ] xrs700x_read_port_counters() updates the stats from a worker using the u64_stats_update_begin() version. This is okay on 32-UP since on the reader side preemption is disabled. On 32bit-SMP the writer can be preempted by the reader at which point the reader will spin on the seqcount until writer continues and completes the update. Assigning the mib_mutex mutex to the underlying seqcount would ensure proper synchronisation. The API for that on the u64_stats_init() side isn't available. Since it is the only user, just use disable interrupts during the update. Use u64_stats_update_begin_irqsave() on the writer side to ensure an uninterrupted update. Fixes: ee00b24f32eb8 ("net: dsa: add Arrow SpeedChips XRS700x driver") Cc: Andrew Lunn Cc: Florian Fainelli Cc: George McCollister Cc: Vivien Didelot Cc: Vladimir Oltean Signed-off-by: Sebastian Andrzej Siewior Acked-by: George McCollister Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/dsa/xrs700x/xrs700x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index 469420941054e..cf363d5a30020 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -108,6 +108,7 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port) { struct xrs700x_port *p = &priv->ports[port]; struct rtnl_link_stats64 stats; + unsigned long flags; int i; memset(&stats, 0, sizeof(stats)); @@ -137,9 +138,9 @@ static void xrs700x_read_port_counters(struct xrs700x *priv, int port) */ stats.rx_packets += stats.multicast; - u64_stats_update_begin(&p->syncp); + flags = u64_stats_update_begin_irqsave(&p->syncp); p->stats64 = stats; - u64_stats_update_end(&p->syncp); + u64_stats_update_end_irqrestore(&p->syncp, flags); mutex_unlock(&p->mib_mutex); } From ce881ddbdc028fb1988b66e40e45ca0529c23b46 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Fri, 26 Aug 2022 09:39:30 +0800 Subject: [PATCH 021/228] net: sched: tbf: don't call qdisc_put() while holding tree lock [ Upstream commit b05972f01e7d30419987a1f221b5593668fd6448 ] The issue is the same to commit c2999f7fb05b ("net: sched: multiq: don't call qdisc_put() while holding tree lock"). Qdiscs call qdisc_put() while holding sch tree spinlock, which results sleeping-while-atomic BUG. Fixes: c266f64dbfa2 ("net: sched: protect block state with mutex") Signed-off-by: Zhengchao Shao Link: https://lore.kernel.org/r/20220826013930.340121-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/sched/sch_tbf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 78e79029dc631..6eb17004a9e44 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -342,6 +342,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, struct nlattr *tb[TCA_TBF_MAX + 1]; struct tc_tbf_qopt *qopt; struct Qdisc *child = NULL; + struct Qdisc *old = NULL; struct psched_ratecfg rate; struct psched_ratecfg peak; u64 max_size; @@ -433,7 +434,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, sch_tree_lock(sch); if (child) { qdisc_tree_flush_backlog(q->qdisc); - qdisc_put(q->qdisc); + old = q->qdisc; q->qdisc = child; } q->limit = qopt->limit; @@ -453,6 +454,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg)); sch_tree_unlock(sch); + qdisc_put(old); err = 0; tbf_offload_change(sch); From a420d587260185407eda9c5766cfa9bdd5c39a56 Mon Sep 17 00:00:00 2001 From: Wang Hai Date: Fri, 26 Aug 2022 17:00:55 +0800 Subject: [PATCH 022/228] net/sched: fix netdevice reference leaks in attach_default_qdiscs() [ Upstream commit f612466ebecb12a00d9152344ddda6f6345f04dc ] In attach_default_qdiscs(), if a dev has multiple queues and queue 0 fails to attach qdisc because there is no memory in attach_one_default_qdisc(). Then dev->qdisc will be noop_qdisc by default. But the other queues may be able to successfully attach to default qdisc. In this case, the fallback to noqueue process will be triggered. If the original attached qdisc is not released and a new one is directly attached, this will cause netdevice reference leaks. The following is the bug log: veth0: default qdisc (fq_codel) fail, fallback to noqueue unregister_netdevice: waiting for veth0 to become free. Usage count = 32 leaked reference. qdisc_alloc+0x12e/0x210 qdisc_create_dflt+0x62/0x140 attach_one_default_qdisc.constprop.41+0x44/0x70 dev_activate+0x128/0x290 __dev_open+0x12a/0x190 __dev_change_flags+0x1a2/0x1f0 dev_change_flags+0x23/0x60 do_setlink+0x332/0x1150 __rtnl_newlink+0x52f/0x8e0 rtnl_newlink+0x43/0x70 rtnetlink_rcv_msg+0x140/0x3b0 netlink_rcv_skb+0x50/0x100 netlink_unicast+0x1bb/0x290 netlink_sendmsg+0x37c/0x4e0 sock_sendmsg+0x5f/0x70 ____sys_sendmsg+0x208/0x280 Fix this bug by clearing any non-noop qdiscs that may have been assigned before trying to re-attach. Fixes: bf6dba76d278 ("net: sched: fallback to qdisc noqueue if default qdisc setup fail") Signed-off-by: Wang Hai Link: https://lore.kernel.org/r/20220826090055.24424-1-wanghai38@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/sched/sch_generic.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 250d87d993cb7..02299785209c1 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -1083,6 +1083,21 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, } EXPORT_SYMBOL(dev_graft_qdisc); +static void shutdown_scheduler_queue(struct net_device *dev, + struct netdev_queue *dev_queue, + void *_qdisc_default) +{ + struct Qdisc *qdisc = dev_queue->qdisc_sleeping; + struct Qdisc *qdisc_default = _qdisc_default; + + if (qdisc) { + rcu_assign_pointer(dev_queue->qdisc, qdisc_default); + dev_queue->qdisc_sleeping = qdisc_default; + + qdisc_put(qdisc); + } +} + static void attach_one_default_qdisc(struct net_device *dev, struct netdev_queue *dev_queue, void *_unused) @@ -1130,6 +1145,7 @@ static void attach_default_qdiscs(struct net_device *dev) if (qdisc == &noop_qdisc) { netdev_warn(dev, "default qdisc (%s) fail, fallback to %s\n", default_qdisc_ops->id, noqueue_qdisc_ops.id); + netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); dev->priv_flags |= IFF_NO_QUEUE; netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); qdisc = txq->qdisc_sleeping; @@ -1384,21 +1400,6 @@ void dev_init_scheduler(struct net_device *dev) timer_setup(&dev->watchdog_timer, dev_watchdog, 0); } -static void shutdown_scheduler_queue(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_qdisc_default) -{ - struct Qdisc *qdisc = dev_queue->qdisc_sleeping; - struct Qdisc *qdisc_default = _qdisc_default; - - if (qdisc) { - rcu_assign_pointer(dev_queue->qdisc, qdisc_default); - dev_queue->qdisc_sleeping = qdisc_default; - - qdisc_put(qdisc); - } -} - void dev_shutdown(struct net_device *dev) { netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); From a4c08cbfbcf9b02bc4c54e6f141283e2e0dfae18 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Sat, 27 Aug 2022 23:38:15 +0800 Subject: [PATCH 023/228] ethernet: rocker: fix sleep in atomic context bug in neigh_timer_handler [ Upstream commit c0955bf957be4bead01fae1d791476260da7325d ] The function neigh_timer_handler() is a timer handler that runs in an atomic context. When used by rocker, neigh_timer_handler() calls "kzalloc(.., GFP_KERNEL)" that may sleep. As a result, the sleep in atomic context bug will happen. One of the processes is shown below: ofdpa_fib4_add() ... neigh_add_timer() (wait a timer) neigh_timer_handler() neigh_release() neigh_destroy() rocker_port_neigh_destroy() rocker_world_port_neigh_destroy() ofdpa_port_neigh_destroy() ofdpa_port_ipv4_neigh() kzalloc(sizeof(.., GFP_KERNEL) //may sleep This patch changes the gfp_t parameter of kzalloc() from GFP_KERNEL to GFP_ATOMIC in order to mitigate the bug. Fixes: 00fc0c51e35b ("rocker: Change world_ops API and implementation to be switchdev independant") Signed-off-by: Duoming Zhou Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index bc70c6abd6a5b..58cf7cc54f408 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1273,7 +1273,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, bool removing; int err = 0; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) return -ENOMEM; From 660df4411ef494db2da042024674ebd3cd4c15bf Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 26 Aug 2022 11:59:16 -0400 Subject: [PATCH 024/228] mlxbf_gige: compute MDIO period based on i1clk [ Upstream commit 3a1a274e933fca73fdc960cb1f60636cd285a265 ] This patch adds logic to compute the MDIO period based on the i1clk, and thereafter write the MDIO period into the YU MDIO config register. The i1clk resource from the ACPI table is used to provide addressing to YU bootrecord PLL registers. The values in these registers are used to compute MDIO period. If the i1clk resource is not present in the ACPI table, then the current default hardcorded value of 430Mhz is used. The i1clk clock value of 430MHz is only accurate for boards with BF2 mid bin and main bin SoCs. The BF2 high bin SoCs have i1clk = 500MHz, but can support a slower MDIO period. Fixes: f92e1869d74e ("Add Mellanox BlueField Gigabit Ethernet driver") Reviewed-by: Asmaa Mnebhi Signed-off-by: David Thompson Link: https://lore.kernel.org/r/20220826155916.12491-1-davthompson@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 4 +- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 122 +++++++++++++++--- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 2 + 3 files changed, 110 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index e3509e69ed1c6..3e8725b7f0b70 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -80,6 +80,7 @@ struct mlxbf_gige { struct net_device *netdev; struct platform_device *pdev; void __iomem *mdio_io; + void __iomem *clk_io; struct mii_bus *mdiobus; void __iomem *gpio_io; struct irq_domain *irqdomain; @@ -149,7 +150,8 @@ enum mlxbf_gige_res { MLXBF_GIGE_RES_MDIO9, MLXBF_GIGE_RES_GPIO0, MLXBF_GIGE_RES_LLU, - MLXBF_GIGE_RES_PLU + MLXBF_GIGE_RES_PLU, + MLXBF_GIGE_RES_CLK }; /* Version of register data returned by mlxbf_gige_get_regs() */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 7905179a95753..f979ba7e5effc 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -22,10 +22,23 @@ #include #include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 +#define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL +#define MLXBF_GIGE_MDIO_COREPLL_CONST 16384ULL +#define MLXBF_GIGE_MDC_CLK_NS 400 +#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG1 0x4 +#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG2 0x8 +#define MLXBF_GIGE_MDIO_CORE_F_SHIFT 0 +#define MLXBF_GIGE_MDIO_CORE_F_MASK GENMASK(25, 0) +#define MLXBF_GIGE_MDIO_CORE_R_SHIFT 26 +#define MLXBF_GIGE_MDIO_CORE_R_MASK GENMASK(31, 26) +#define MLXBF_GIGE_MDIO_CORE_OD_SHIFT 0 +#define MLXBF_GIGE_MDIO_CORE_OD_MASK GENMASK(3, 0) + /* Support clause 22 */ #define MLXBF_GIGE_MDIO_CL22_ST1 0x1 #define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 @@ -50,27 +63,76 @@ #define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) #define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) +#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) + +#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 +#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c + +static struct resource corepll_params[] = { + [MLXBF_GIGE_VERSION_BF2] = { + .start = MLXBF_GIGE_BF2_COREPLL_ADDR, + .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, + .name = "COREPLL_RES" + }, +}; + +/* Returns core clock i1clk in Hz */ +static u64 calculate_i1clk(struct mlxbf_gige *priv) +{ + u8 core_od, core_r; + u64 freq_output; + u32 reg1, reg2; + u32 core_f; + + reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1); + reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2); + + core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >> + MLXBF_GIGE_MDIO_CORE_F_SHIFT; + core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >> + MLXBF_GIGE_MDIO_CORE_R_SHIFT; + core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >> + MLXBF_GIGE_MDIO_CORE_OD_SHIFT; + + /* Compute PLL output frequency as follow: + * + * CORE_F / 16384 + * freq_output = freq_reference * ---------------------------- + * (CORE_R + 1) * (CORE_OD + 1) + */ + freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f), + MLXBF_GIGE_MDIO_COREPLL_CONST); + freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1)); + + return freq_output; +} + /* Formula for encoding the MDIO period. The encoded value is * passed to the MDIO config register. * - * mdc_clk = 2*(val + 1)*i1clk + * mdc_clk = 2*(val + 1)*(core clock in sec) * - * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) + * i1clk is in Hz: + * 400 ns = 2*(val + 1)*(1/i1clk) * - * val = (((400 * 430 / 1000) / 2) - 1) + * val = (((400/10^9) / (1/i1clk) / 2) - 1) + * val = (400/2 * i1clk)/10^9 - 1 */ -#define MLXBF_GIGE_I1CLK_MHZ 430 -#define MLXBF_GIGE_MDC_CLK_NS 400 +static u8 mdio_period_map(struct mlxbf_gige *priv) +{ + u8 mdio_period; + u64 i1clk; -#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) + i1clk = calculate_i1clk(priv); -#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ - MLXBF_GIGE_MDIO_PERIOD) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) + mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1; + + return mdio_period; +} static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, int phy_reg, u32 opcode) @@ -123,9 +185,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, int phy_reg, u16 val) { struct mlxbf_gige *priv = bus->priv; + u32 temp; u32 cmd; int ret; - u32 temp; if (phy_reg & MII_ADDR_C45) return -EOPNOTSUPP; @@ -142,18 +204,44 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, return ret; } +static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv) +{ + u8 mdio_period; + u32 val; + + mdio_period = mdio_period_map(priv); + + val = MLXBF_GIGE_MDIO_CFG_VAL; + val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); + writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); +} + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) { struct device *dev = &pdev->dev; + struct resource *res; int ret; priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9); if (IS_ERR(priv->mdio_io)) return PTR_ERR(priv->mdio_io); - /* Configure mdio parameters */ - writel(MLXBF_GIGE_MDIO_CFG_VAL, - priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); + /* clk resource shared with other drivers so cannot use + * devm_platform_ioremap_resource + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); + if (!res) { + /* For backward compatibility with older ACPI tables, also keep + * CLK resource internal to the driver. + */ + res = &corepll_params[MLXBF_GIGE_VERSION_BF2]; + } + + priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(priv->clk_io)) + return PTR_ERR(priv->clk_io); + + mlxbf_gige_mdio_cfg(priv); priv->mdiobus = devm_mdiobus_alloc(dev); if (!priv->mdiobus) { diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 5fb33c9294bf9..7be3a793984d5 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -8,6 +8,8 @@ #ifndef __MLXBF_GIGE_REGS_H__ #define __MLXBF_GIGE_REGS_H__ +#define MLXBF_GIGE_VERSION 0x0000 +#define MLXBF_GIGE_VERSION_BF2 0x0 #define MLXBF_GIGE_STATUS 0x0010 #define MLXBF_GIGE_STATUS_READY BIT(0) #define MLXBF_GIGE_INT_STATUS 0x0028 From 55fb8c3baa8071c5d533a9ad48624e44e2a04ef5 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sat, 27 Aug 2022 11:13:14 -0700 Subject: [PATCH 025/228] kcm: fix strp_init() order and cleanup [ Upstream commit 8fc29ff3910f3af08a7c40a75d436b5720efe2bf ] strp_init() is called just a few lines above this csk->sk_user_data check, it also initializes strp->work etc., therefore, it is unnecessary to call strp_done() to cancel the freshly initialized work. And if sk_user_data is already used by KCM, psock->strp should not be touched, particularly strp->work state, so we need to move strp_init() after the csk->sk_user_data check. This also makes a lockdep warning reported by syzbot go away. Reported-and-tested-by: syzbot+9fc084a4348493ef65d2@syzkaller.appspotmail.com Reported-by: syzbot+e696806ef96cdd2d87cd@syzkaller.appspotmail.com Fixes: e5571240236c ("kcm: Check if sk_user_data already set in kcm_attach") Fixes: dff8baa26117 ("kcm: Call strp_stop before strp_done in kcm_attach") Cc: Tom Herbert Signed-off-by: Cong Wang Link: https://lore.kernel.org/r/20220827181314.193710-1-xiyou.wangcong@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/kcm/kcmsock.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 11a715d76a4f1..f780fbe82e7dc 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1411,12 +1411,6 @@ static int kcm_attach(struct socket *sock, struct socket *csock, psock->sk = csk; psock->bpf_prog = prog; - err = strp_init(&psock->strp, csk, &cb); - if (err) { - kmem_cache_free(kcm_psockp, psock); - goto out; - } - write_lock_bh(&csk->sk_callback_lock); /* Check if sk_user_data is already by KCM or someone else. @@ -1424,13 +1418,18 @@ static int kcm_attach(struct socket *sock, struct socket *csock, */ if (csk->sk_user_data) { write_unlock_bh(&csk->sk_callback_lock); - strp_stop(&psock->strp); - strp_done(&psock->strp); kmem_cache_free(kcm_psockp, psock); err = -EALREADY; goto out; } + err = strp_init(&psock->strp, csk, &cb); + if (err) { + write_unlock_bh(&csk->sk_callback_lock); + kmem_cache_free(kcm_psockp, psock); + goto out; + } + psock->save_data_ready = csk->sk_data_ready; psock->save_write_space = csk->sk_write_space; psock->save_state_change = csk->sk_state_change; From 1c472d671d9c51c02bb54ee1c5b22e96ea5fe933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Wed, 31 Aug 2022 11:21:03 +0200 Subject: [PATCH 026/228] sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 90fabae8a2c225c4e4936723c38857887edde5cc ] When the GSO splitting feature of sch_cake is enabled, GSO superpackets will be broken up and the resulting segments enqueued in place of the original skb. In this case, CAKE calls consume_skb() on the original skb, but still returns NET_XMIT_SUCCESS. This can confuse parent qdiscs into assuming the original skb still exists, when it really has been freed. Fix this by adding the __NET_XMIT_STOLEN flag to the return value in this case. Fixes: 0c850344d388 ("sch_cake: Conditionally split GSO segments") Signed-off-by: Toke Høiland-Jørgensen Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-18231 Link: https://lore.kernel.org/r/20220831092103.442868-1-toke@toke.dk Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/sch_cake.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 857aaebd49f43..6944c669731c4 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1713,6 +1713,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, } idx--; flow = &b->flows[idx]; + ret = NET_XMIT_SUCCESS; /* ensure shaper state isn't stale */ if (!b->tin_backlog) { @@ -1771,6 +1772,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); consume_skb(skb); + ret |= __NET_XMIT_STOLEN; } else { /* not splitting */ cobalt_set_enqueue_time(skb, now); @@ -1904,7 +1906,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, } b->drop_overlimit += dropped; } - return NET_XMIT_SUCCESS; + return ret; } static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) From aca9d0acda9e8912a1a2eaba0c062b29731d4fe7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 30 Aug 2022 11:56:55 -0700 Subject: [PATCH 027/228] tcp: annotate data-race around challenge_timestamp [ Upstream commit 8c70521238b7863c2af607e20bcba20f974c969b ] challenge_timestamp can be read an written by concurrent threads. This was expected, but we need to annotate the race to avoid potential issues. Following patch moves challenge_timestamp and challenge_count to per-netns storage to provide better isolation. Fixes: 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") Reported-by: syzbot Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a33e6aa42a4c5..7fd7e7cba0c92 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3623,11 +3623,11 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) /* Then check host-wide RFC 5961 rate limit. */ now = jiffies / HZ; - if (now != challenge_timestamp) { + if (now != READ_ONCE(challenge_timestamp)) { u32 ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); u32 half = (ack_limit + 1) >> 1; - challenge_timestamp = now; + WRITE_ONCE(challenge_timestamp, now); WRITE_ONCE(challenge_count, half + prandom_u32_max(ack_limit)); } count = READ_ONCE(challenge_count); From 6ce0d73b2fbdc5a33be649923692991d6b9af397 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 Aug 2022 20:01:32 -0700 Subject: [PATCH 028/228] Revert "sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb" [ Upstream commit 0b4f688d53fdc2a731b9d9cdf0c96255bc024ea6 ] This reverts commit 90fabae8a2c225c4e4936723c38857887edde5cc. Patch was applied hastily, revert and let the v2 be reviewed. Fixes: 90fabae8a2c2 ("sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb") Link: https://lore.kernel.org/all/87wnao2ha3.fsf@toke.dk/ Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/sch_cake.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 6944c669731c4..857aaebd49f43 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1713,7 +1713,6 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, } idx--; flow = &b->flows[idx]; - ret = NET_XMIT_SUCCESS; /* ensure shaper state isn't stale */ if (!b->tin_backlog) { @@ -1772,7 +1771,6 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); consume_skb(skb); - ret |= __NET_XMIT_STOLEN; } else { /* not splitting */ cobalt_set_enqueue_time(skb, now); @@ -1906,7 +1904,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, } b->drop_overlimit += dropped; } - return ret; + return NET_XMIT_SUCCESS; } static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) From fdc69b070071eb644c94a5e5e72da7b10b975220 Mon Sep 17 00:00:00 2001 From: Yacan Liu Date: Tue, 30 Aug 2022 23:23:14 +0800 Subject: [PATCH 029/228] net/smc: Remove redundant refcount increase [ Upstream commit a8424a9b4522a3ab9f32175ad6d848739079071f ] For passive connections, the refcount increment has been done in smc_clcsock_accept()-->smc_sock_alloc(). Fixes: 3b2dec2603d5 ("net/smc: restructure client and server code in af_smc") Signed-off-by: Yacan Liu Reviewed-by: Tony Lu Link: https://lore.kernel.org/r/20220830152314.838736-1-liuyacan@corp.netease.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/smc/af_smc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 2ddd7b34b4ce5..26f81e2e1dfba 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1490,7 +1490,6 @@ static void smc_listen_out_connected(struct smc_sock *new_smc) { struct sock *newsmcsk = &new_smc->sk; - sk_refcnt_debug_inc(newsmcsk); if (newsmcsk->sk_state == SMC_INIT) newsmcsk->sk_state = SMC_ACTIVE; From 839ca7969fcfc975e3898d9148b77705315c9a07 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 8 Jul 2022 11:47:47 +0100 Subject: [PATCH 030/228] soundwire: qcom: fix device status array range [ Upstream commit 4ef3f2aff1267bfa6d5a90c42a30b927b8aa239b ] This patch updates device status array range from 11 to 12 as we will be reading status from device number 0 to device number 11 inclusive. Without this patch we can potentially access status array out of range during auto-enumeration. Fixes: aa1262ca6695 ("soundwire: qcom: Check device status before reading devid") Reported-by: Dan Carpenter Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220708104747.8722-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/qcom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 2adc0a75c0515..1ce6f948e9a42 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -148,7 +148,7 @@ struct qcom_swrm_ctrl { u8 wcmd_id; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; - enum sdw_slave_status status[SDW_MAX_DEVICES]; + enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); u32 slave_status; @@ -391,7 +391,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); - for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) { + for (dev_num = 0; dev_num <= SDW_MAX_DEVICES; dev_num++) { status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { @@ -411,7 +411,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); ctrl->slave_status = val; - for (i = 0; i < SDW_MAX_DEVICES; i++) { + for (i = 0; i <= SDW_MAX_DEVICES; i++) { u32 s; s = (val >> (i * 2)); From 01fd7e12f8fb1fe95cc650df680ed87435bbf24e Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Fri, 5 Aug 2022 09:45:29 -0500 Subject: [PATCH 031/228] serial: fsl_lpuart: RS485 RTS polariy is inverse commit 846651eca073e2e02e37490a4a52752415d84781 upstream. The setting of RS485 RTS polarity is inverse in the current driver. When the property of 'rs485-rts-active-low' is enabled in the dts node, the RTS signal should be LOW during sending. Otherwise, if there is no such a property, the RTS should be HIGH during sending. Fixes: 03895cf41d18 ("tty: serial: fsl_lpuart: Add support for RS-485") Cc: stable Signed-off-by: Nicolas Diaz Signed-off-by: Shenwei Wang Link: https://lore.kernel.org/r/20220805144529.604856-1-shenwei.wang@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 4155bd10711da..127dd937ee51b 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1381,9 +1381,9 @@ static int lpuart_config_rs485(struct uart_port *port, * Note: UART is assumed to be active high. */ if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem &= ~UARTMODEM_TXRTSPOL; - else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) modem |= UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem &= ~UARTMODEM_TXRTSPOL; } /* Store the new configuration */ From dc02aaf950015850e7589696521c7fca767cea77 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 30 Aug 2022 17:55:07 +0300 Subject: [PATCH 032/228] staging: rtl8712: fix use after free bugs commit e230a4455ac3e9b112f0367d1b8e255e141afae0 upstream. _Read/Write_MACREG callbacks are NULL so the read/write_macreg_hdl() functions don't do anything except free the "pcmd" pointer. It results in a use after free. Delete them. Fixes: 2865d42c78a9 ("staging: r8712u: Add the new driver to the mainline kernel") Cc: stable Reported-by: Zheng Wang Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yw4ASqkYcUhUfoY2@kili Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_cmd.c | 36 --------------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c index e9294e1ed06eb..eacf5efa34307 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/drivers/staging/rtl8712/rtl8712_cmd.c @@ -117,34 +117,6 @@ static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf) kfree(pdrvcmd->pbuf); } -static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - /* invoke cmd->callback function */ - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); - return H2C_SUCCESS; -} - -static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - /* invoke cmd->callback function */ - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); - return H2C_SUCCESS; -} - static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) { struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; @@ -213,14 +185,6 @@ static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter, pcmd_r = NULL; switch (pcmd->cmdcode) { - case GEN_CMD_CODE(_Read_MACREG): - read_macreg_hdl(padapter, (u8 *)pcmd); - pcmd_r = pcmd; - break; - case GEN_CMD_CODE(_Write_MACREG): - write_macreg_hdl(padapter, (u8 *)pcmd); - pcmd_r = pcmd; - break; case GEN_CMD_CODE(_Read_BBREG): read_bbreg_hdl(padapter, (u8 *)pcmd); break; From f12afb4b5db01c4baf39eb2e6a5e2ff8074a7b8f Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Tue, 2 Aug 2022 19:18:44 +0200 Subject: [PATCH 033/228] staging: r8188eu: add firmware dependency commit b2fa9e13bbf101c662c4cd974608242a0db98cfc upstream. The old rtl8188eu module, removed in commit 55dfa29b43d2 ("staging: rtl8188eu: remove rtl8188eu driver from staging dir") (Linux kernel v5.15-rc1), required (through a MODULE_FIRMWARE call()) the rtlwifi/rtl8188eufw.bin firmware file, which the new r8188eu driver no longer requires. I have tested a few RTL8188EUS-based Wi-Fi cards and, while supported by both drivers, they do not work when using the new one and the firmware wasn't manually loaded. According to Larry Finger, the module maintainer, all such cards need the firmware and the driver should depend on it (see the linked mails). Add a proper MODULE_FIRMWARE() call, like it was done in the old driver. Thanks to Greg Kroah-Hartman and Larry Finger for quick responses to my questions. Cc: stable Link: https://answers.launchpad.net/ubuntu/+source/linux-meta-hwe-5.15/+question/702611 Link: https://lore.kernel.org/lkml/YukkBu3TNODO3or9@nx64de-df6d00/ Signed-off-by: Grzegorz Szymaszek Link: https://lore.kernel.org/r/YulcdKfhA8dPQ78s@nx64de-df6d00 Acked-by: Phillip Potter Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/os_dep/os_intfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c index 8d0158f4a45d0..30caa1139c8eb 100644 --- a/drivers/staging/r8188eu/os_dep/os_intfs.c +++ b/drivers/staging/r8188eu/os_dep/os_intfs.c @@ -17,6 +17,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); MODULE_AUTHOR("Realtek Semiconductor Corp."); MODULE_VERSION(DRIVERVERSION); +MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin"); #define CONFIG_BR_EXT_BRNAME "br0" #define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */ From a19846f0f45beaa4eb4e0f548ae610fbb420980e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 21 Aug 2022 01:51:29 +0900 Subject: [PATCH 034/228] powerpc: align syscall table for ppc32 commit c7acee3d2f128a38b68fb7af85dbbd91bfd0b4ad upstream. Christophe Leroy reported that commit 7b4537199a4a ("kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS") broke mpc85xx_defconfig + CONFIG_RELOCATABLE=y. LD vmlinux SYSMAP System.map SORTTAB vmlinux CHKREL vmlinux WARNING: 451 bad relocations c0b312a9 R_PPC_UADDR32 .head.text-0x3ff9ed54 c0b312ad R_PPC_UADDR32 .head.text-0x3ffac224 c0b312b1 R_PPC_UADDR32 .head.text-0x3ffb09f4 c0b312b5 R_PPC_UADDR32 .head.text-0x3fe184dc c0b312b9 R_PPC_UADDR32 .head.text-0x3fe183a8 ... The compiler emits a bunch of R_PPC_UADDR32, which is not supported by arch/powerpc/kernel/reloc_32.S. The reason is there exists an unaligned symbol. $ powerpc-linux-gnu-nm -n vmlinux ... c0b31258 d spe_aligninfo c0b31298 d __func__.0 c0b312a9 D sys_call_table c0b319b8 d __func__.0 Commit 7b4537199a4a is not the root cause. Even before that, I can reproduce the same issue for mpc85xx_defconfig + CONFIG_RELOCATABLE=y + CONFIG_MODVERSIONS=n. It is just that nobody noticed because when CONFIG_MODVERSIONS is enabled, a __crc_* symbol inserted before sys_call_table was hiding the unalignment issue. Adding alignment to the syscall table for ppc32 fixes the issue. Cc: stable@vger.kernel.org Reported-by: Christophe Leroy Signed-off-by: Masahiro Yamada Tested-by: Christophe Leroy [mpe: Trim change log discussion, add Cc stable] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/lkml/38605f6a-a568-f884-f06f-ea4da5b214f0@csgroup.eu/ Link: https://lore.kernel.org/r/20220820165129.1147589-1-masahiroy@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/systbl.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index cb3358886203e..6c1db3b6de2dc 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -18,6 +18,7 @@ .p2align 3 #define __SYSCALL(nr, entry) .8byte entry #else + .p2align 2 #define __SYSCALL(nr, entry) .long entry #endif From 2535431ae967ad17585513649625fea7db28d4db Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 30 Jul 2022 20:50:18 +0200 Subject: [PATCH 035/228] vt: Clear selection before changing the font commit 566f9c9f89337792070b5a6062dff448b3e7977f upstream. When changing the console font with ioctl(KDFONTOP) the new font size can be bigger than the previous font. A previous selection may thus now be outside of the new screen size and thus trigger out-of-bounds accesses to graphics memory if the selection is removed in vc_do_resize(). Prevent such out-of-memory accesses by dropping the selection before the various con_font_set() console handlers are called. Reported-by: syzbot+14b0e8f3fd1612e35350@syzkaller.appspotmail.com Cc: stable Tested-by: Khalid Masum Signed-off-by: Helge Deller Link: https://lore.kernel.org/r/YuV9apZGNmGfjcor@p100 Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6eaf8eb846619..b8f5bc19416d9 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4662,9 +4662,11 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) console_lock(); if (vc->vc_mode != KD_TEXT) rc = -EINVAL; - else if (vc->vc_sw->con_font_set) + else if (vc->vc_sw->con_font_set) { + if (vc_is_sel(vc)) + clear_selection(); rc = vc->vc_sw->con_font_set(vc, &font, op->flags); - else + } else rc = -ENOSYS; console_unlock(); kfree(font.data); @@ -4691,9 +4693,11 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) console_unlock(); return -EINVAL; } - if (vc->vc_sw->con_font_default) + if (vc->vc_sw->con_font_default) { + if (vc_is_sel(vc)) + clear_selection(); rc = vc->vc_sw->con_font_default(vc, &font, s); - else + } else rc = -ENOSYS; console_unlock(); if (!rc) { From 532b255af19507f7b9a965e1dc4b2e15ee4fcc37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Aug 2022 15:57:20 +0200 Subject: [PATCH 036/228] musb: fix USB_MUSB_TUSB6010 dependency commit a3f2fd22743fc56dd5e3896a3fbddd276df1577f upstream. Turning on NOP_USB_XCEIV as builtin broke the TUSB6010 driver because of an older issue with the depencency. It is not necessary to forbid NOP_USB_XCEIV=y in combination with USB_MUSB_HDRC=m, but only the reverse, which causes the link failure from the original Kconfig change. Use the correct dependency to still allow NOP_USB_XCEIV=n or NOP_USB_XCEIV=y but forbid NOP_USB_XCEIV=m when USB_MUSB_HDRC=m to fix the multi_v7_defconfig for tusb. Fixes: ab37a7a890c1 ("ARM: multi_v7_defconfig: Make NOP_USB_XCEIV driver built-in") Fixes: c0442479652b ("usb: musb: Fix randconfig build issues for Kconfig options") Cc: stable Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20220818135737.3143895-10-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 4d61df6a9b5c8..70693cae83efb 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -86,7 +86,7 @@ config USB_MUSB_TUSB6010 tristate "TUSB6010" depends on HAS_IOMEM depends on ARCH_OMAP2PLUS || COMPILE_TEST - depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules + depends on NOP_USB_XCEIV!=m || USB_MUSB_HDRC=m config USB_MUSB_OMAP2PLUS tristate "OMAP2430 and onwards" From 9f185ca8e019bf31fa70a38ff949565a92abf2ed Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Sun, 21 Aug 2022 18:15:27 +0800 Subject: [PATCH 037/228] tty: serial: lpuart: disable flow control while waiting for the transmit engine to complete commit d5a2e0834364377a5d5a2fff1890a0b3f0bafd1f upstream. When the user initializes the uart port, and waits for the transmit engine to complete in lpuart32_set_termios(), if the UART TX fifo has dirty data and the UARTMODIR enable the flow control, the TX fifo may never be empty. So here we should disable the flow control first to make sure the transmit engin can complete. Fixes: 380c966c093e ("tty: serial: fsl_lpuart: add 32-bit register interface support") Cc: stable Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20220821101527.10066-1-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 127dd937ee51b..bf11ffafcad53 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2203,6 +2203,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ + lpuart32_write(&sport->port, 0, UARTMODIR); lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); /* disable transmit and receive */ From df1b53bc799d58f79701c465505a206c72ad4ab8 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 27 Aug 2022 20:36:27 -0700 Subject: [PATCH 038/228] Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flag commit 98e01215708b6d416345465c09dce2bd4868c67a upstream. syzbot is reporting hung task at __input_unregister_device() [1], for iforce_close() waiting at wait_event_interruptible() with dev->mutex held is blocking input_disconnect_device() from __input_unregister_device(). It seems that the cause is simply that commit c2b27ef672992a20 ("Input: iforce - wait for command completion when closing the device") forgot to call wake_up() after clear_bit(). Fix this problem by introducing a helper that calls clear_bit() followed by wake_up_all(). Reported-by: syzbot Fixes: c2b27ef672992a20 ("Input: iforce - wait for command completion when closing the device") Tested-by: syzbot Suggested-by: Fabio M. De Francesco Co-developed-by: Hillf Danton Signed-off-by: Hillf Danton Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/r/887021c3-4f13-40ce-c8b9-aa6e09faa3a7@I-love.SAKURA.ne.jp Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/iforce/iforce-serio.c | 6 +++--- drivers/input/joystick/iforce/iforce-usb.c | 8 ++++---- drivers/input/joystick/iforce/iforce.h | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index f95a81b9fac72..2380546d79782 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -39,7 +39,7 @@ static void iforce_serio_xmit(struct iforce *iforce) again: if (iforce->xmit.head == iforce->xmit.tail) { - clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + iforce_clear_xmit_and_wake(iforce); spin_unlock_irqrestore(&iforce->xmit_lock, flags); return; } @@ -64,7 +64,7 @@ static void iforce_serio_xmit(struct iforce *iforce) if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) goto again; - clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + iforce_clear_xmit_and_wake(iforce); spin_unlock_irqrestore(&iforce->xmit_lock, flags); } @@ -169,7 +169,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, iforce_serio->cmd_response_len = iforce_serio->len; /* Signal that command is done */ - wake_up(&iforce->wait); + wake_up_all(&iforce->wait); } else if (likely(iforce->type)) { iforce_process_packet(iforce, iforce_serio->id, iforce_serio->data_in, diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index ea58805c480fa..cba92bd590a8d 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -30,7 +30,7 @@ static void __iforce_usb_xmit(struct iforce *iforce) spin_lock_irqsave(&iforce->xmit_lock, flags); if (iforce->xmit.head == iforce->xmit.tail) { - clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + iforce_clear_xmit_and_wake(iforce); spin_unlock_irqrestore(&iforce->xmit_lock, flags); return; } @@ -58,9 +58,9 @@ static void __iforce_usb_xmit(struct iforce *iforce) XMIT_INC(iforce->xmit.tail, n); if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { - clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); dev_warn(&iforce_usb->intf->dev, "usb_submit_urb failed %d\n", n); + iforce_clear_xmit_and_wake(iforce); } /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. @@ -175,15 +175,15 @@ static void iforce_usb_out(struct urb *urb) struct iforce *iforce = &iforce_usb->iforce; if (urb->status) { - clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n", urb->status); + iforce_clear_xmit_and_wake(iforce); return; } __iforce_usb_xmit(iforce); - wake_up(&iforce->wait); + wake_up_all(&iforce->wait); } static int iforce_usb_probe(struct usb_interface *intf, diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 6aa761ebbdf77..9ccb9107ccbef 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -119,6 +119,12 @@ static inline int iforce_get_id_packet(struct iforce *iforce, u8 id, response_data, response_len); } +static inline void iforce_clear_xmit_and_wake(struct iforce *iforce) +{ + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + wake_up_all(&iforce->wait); +} + /* Public functions */ /* iforce-main.c */ int iforce_init_device(struct device *parent, u16 bustype, From 6e933a26e6a2e3d40ed9a269ddb4e0e3ed3ecdb5 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 19 Aug 2022 11:51:07 +0300 Subject: [PATCH 039/228] iio: ad7292: Prevent regulator double disable commit 22b4277641c6823ec03d5b1cd82628e5e53e75b7 upstream. The ad7292 tries to add an devm_action for disabling a regulator at device detach using devm_add_action_or_reset(). The devm_add_action_or_reset() does call the release function should adding action fail. The driver inspects the value returned by devm_add_action_or_reset() and manually calls regulator_disable() if adding the action has failed. This leads to double disable and messes the enable count for regulator. Do not manually call disable if devm_add_action_or_reset() fails. Fixes: 506d2e317a0a ("iio: adc: Add driver support for AD7292") Signed-off-by: Matti Vaittinen Tested-by: Marcelo Schmitt Link: https://lore.kernel.org/r/Yv9O+9sxU7gAv3vM@fedora Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ad7292.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 3271a31afde1c..e3e14a1253e89 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -287,10 +287,8 @@ static int ad7292_probe(struct spi_device *spi) ret = devm_add_action_or_reset(&spi->dev, ad7292_regulator_disable, st); - if (ret) { - regulator_disable(st->reg); + if (ret) return ret; - } ret = regulator_get_voltage(st->reg); if (ret < 0) From 95ac9601feb527d4d134960ac69ffb4b386ba3fb Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Fri, 22 Jul 2022 15:07:20 +0200 Subject: [PATCH 040/228] iio: adc: mcp3911: use correct formula for AD conversion commit 9e2238e3ae40d371a1130226e0e740aa1601efa6 upstream. The ADC conversion is actually not rail-to-rail but with a factor 1.5. Make use of this factor when calculating actual voltage. Fixes: 3a89b289df5d ("iio: adc: add support for mcp3911") Signed-off-by: Marcus Folkesson Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220722130726.7627-4-marcus.folkesson@gmail.com Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/mcp3911.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 81eeb00842112..65278270a75ce 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -38,8 +38,8 @@ #define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3) #define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6) -/* Internal voltage reference in uV */ -#define MCP3911_INT_VREF_UV 1200000 +/* Internal voltage reference in mV */ +#define MCP3911_INT_VREF_MV 1200 #define MCP3911_REG_READ(reg, id) ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff) #define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff) @@ -137,11 +137,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, *val = ret / 1000; } else { - *val = MCP3911_INT_VREF_UV; + *val = MCP3911_INT_VREF_MV; } - *val2 = 24; - ret = IIO_VAL_FRACTIONAL_LOG2; + /* + * For 24bit Conversion + * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5 + * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5) + */ + + /* val2 = (2^23 * 1.5) */ + *val2 = 12582912; + ret = IIO_VAL_FRACTIONAL; break; } From 0e33b0f322fecd7a92d9dc186535cdf97940a856 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 29 Aug 2022 10:05:29 +0200 Subject: [PATCH 041/228] misc: fastrpc: fix memory corruption on probe commit 9baa1415d9abdd1e08362ea2dcfadfacee8690b5 upstream. Add the missing sanity check on the probed-session count to avoid corrupting memory beyond the fixed-size slab-allocated session array when there are more than FASTRPC_MAX_SESSIONS sessions defined in the devicetree. Fixes: f6f9279f2bf0 ("misc: fastrpc: Add Qualcomm fastrpc basic driver model") Cc: stable@vger.kernel.org # 5.1 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220829080531.29681-2-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index c7134d2cf69a9..cbb90e0c9ccf5 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1550,6 +1550,11 @@ static int fastrpc_cb_probe(struct platform_device *pdev) of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions); spin_lock_irqsave(&cctx->lock, flags); + if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) { + dev_err(&pdev->dev, "too many sessions\n"); + spin_unlock_irqrestore(&cctx->lock, flags); + return -ENOSPC; + } sess = &cctx->session[cctx->sesscount]; sess->used = false; sess->valid = true; From cf20c3533efc89578ace94fa20a9e63446223c72 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 29 Aug 2022 10:05:30 +0200 Subject: [PATCH 042/228] misc: fastrpc: fix memory corruption on open commit d245f43aab2b61195d8ebb64cef7b5a08c590ab4 upstream. The probe session-duplication overflow check incremented the session count also when there were no more available sessions so that memory beyond the fixed-size slab-allocated session array could be corrupted in fastrpc_session_alloc() on open(). Fixes: f6f9279f2bf0 ("misc: fastrpc: Add Qualcomm fastrpc basic driver model") Cc: stable@vger.kernel.org # 5.1 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220829080531.29681-3-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index cbb90e0c9ccf5..cf5705776c4f6 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1555,7 +1555,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev) spin_unlock_irqrestore(&cctx->lock, flags); return -ENOSPC; } - sess = &cctx->session[cctx->sesscount]; + sess = &cctx->session[cctx->sesscount++]; sess->used = false; sess->valid = true; sess->dev = dev; @@ -1568,13 +1568,12 @@ static int fastrpc_cb_probe(struct platform_device *pdev) struct fastrpc_session_ctx *dup_sess; for (i = 1; i < sessions; i++) { - if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS) + if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) break; - dup_sess = &cctx->session[cctx->sesscount]; + dup_sess = &cctx->session[cctx->sesscount++]; memcpy(dup_sess, sess, sizeof(*dup_sess)); } } - cctx->sesscount++; spin_unlock_irqrestore(&cctx->lock, flags); rc = dma_set_mask(dev, DMA_BIT_MASK(32)); if (rc) { From fc9b5b3f2cccb6d78db8fae2649648c72a98e0e5 Mon Sep 17 00:00:00 2001 From: Niek Nooijens Date: Mon, 1 Aug 2022 10:39:25 +0200 Subject: [PATCH 043/228] USB: serial: ftdi_sio: add Omron CS1W-CIF31 device id commit 001047ea241a9646010b2744451dfbc7289542f3 upstream. works perfectly with: modprobe ftdi_sio echo "0590 00b2" | tee /sys/module/ftdi_sio/drivers/usb-serial\:ftdi_sio/new_id > /dev/null but doing this every reboot is a pain in the ass. Signed-off-by: Niek Nooijens Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index e2a8c33f0cae9..a2ecb3b5d13e6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1045,6 +1045,8 @@ static const struct usb_device_id id_table_combined[] = { /* IDS GmbH devices */ { USB_DEVICE(IDS_VID, IDS_SI31A_PID) }, { USB_DEVICE(IDS_VID, IDS_CM31A_PID) }, + /* Omron devices */ + { USB_DEVICE(OMRON_VID, OMRON_CS1W_CIF31_PID) }, /* U-Blox devices */ { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) }, { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 4e92c165c86bf..31c8ccabbbb78 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -661,6 +661,12 @@ #define INFINEON_TRIBOARD_TC1798_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ #define INFINEON_TRIBOARD_TC2X7_PID 0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */ +/* + * Omron corporation (https://www.omron.com) + */ + #define OMRON_VID 0x0590 + #define OMRON_CS1W_CIF31_PID 0x00b2 + /* * Acton Research Corp. */ From 8bca22970e1c8f220c637131770561f6abecc728 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Aug 2022 10:33:20 +0300 Subject: [PATCH 044/228] mmc: core: Fix UHS-I SD 1.8V workaround branch commit 15c56208c79c340686869c31595c209d1431c5e8 upstream. When introduced, upon success, the 1.8V fixup workaround in mmc_sd_init_card() would branch to practically the end of the function, to a label named "done". Unfortunately, perhaps due to the label name, over time new code has been added that really should have come after "done" not before it. Let's fix the problem by moving the label to the correct place and rename it "cont". Fixes: 045d705dc1fb ("mmc: core: Enable the MMC host software queue for the SD card") Signed-off-by: Adrian Hunter Reviewed-by: Seunghui Lee Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20220815073321.63382-2-adrian.hunter@intel.com Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/sd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 44e134fa04afb..6eeafde2fbaf2 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1491,7 +1491,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, mmc_remove_card(card); goto retry; } - goto done; + goto cont; } } @@ -1527,7 +1527,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, mmc_set_bus_width(host, MMC_BUS_WIDTH_4); } } - +cont: if (!oldcard) { /* Read/parse the extension registers. */ err = sd_read_ext_regs(card); @@ -1559,7 +1559,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, err = -EINVAL; goto free_card; } -done: + host->card = card; return 0; From da3c6d0708e64a36886b7143634d3b0432c04dc0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Aug 2022 10:33:21 +0300 Subject: [PATCH 045/228] mmc: core: Fix inconsistent sd3_bus_mode at UHS-I SD voltage switch failure commit 63f1560930e4e1c4f6279b8ae715c9841fe1a6d3 upstream. If re-initialization results is a different signal voltage, because the voltage switch failed previously, but not this time (or vice versa), then sd3_bus_mode will be inconsistent with the card because the SD_SWITCH command is done only upon first initialization. Fix by always reading SD_SWITCH information during re-initialization, which also means it does not need to be re-read later for the 1.8V fixup workaround. Note, brief testing showed SD_SWITCH took about 1.8ms to 2ms which added about 1% to 1.5% to the re-initialization time, so it's not particularly significant. Reported-by: Seunghui Lee Signed-off-by: Adrian Hunter Reviewed-by: Seunghui Lee Tested-by: Seunghui Lee Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20220815073321.63382-3-adrian.hunter@intel.com Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/sd.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 6eeafde2fbaf2..7e8d4abed602d 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -942,15 +942,16 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, /* Erase init depends on CSD and SSR */ mmc_init_erase(card); - - /* - * Fetch switch information from card. - */ - err = mmc_read_switch(card); - if (err) - return err; } + /* + * Fetch switch information from card. Note, sd3_bus_mode can change if + * voltage switch outcome changes, so do this always. + */ + err = mmc_read_switch(card); + if (err) + return err; + /* * For SPI, enable CRC as appropriate. * This CRC enable is located AFTER the reading of the @@ -1473,26 +1474,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) && mmc_sd_card_using_v18(card) && host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) { - /* - * Re-read switch information in case it has changed since - * oldcard was initialized. - */ - if (oldcard) { - err = mmc_read_switch(card); - if (err) - goto free_card; - } - if (mmc_sd_card_using_v18(card)) { - if (mmc_host_set_uhs_voltage(host) || - mmc_sd_init_uhs_card(card)) { - v18_fixup_failed = true; - mmc_power_cycle(host, ocr); - if (!oldcard) - mmc_remove_card(card); - goto retry; - } - goto cont; + if (mmc_host_set_uhs_voltage(host) || + mmc_sd_init_uhs_card(card)) { + v18_fixup_failed = true; + mmc_power_cycle(host, ocr); + if (!oldcard) + mmc_remove_card(card); + goto retry; } + goto cont; } /* Initialization sequence for UHS-I cards */ From c2a4b5dc8fa71af73bab704d0cac42ac39767ed6 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 1 Aug 2022 18:25:11 +0000 Subject: [PATCH 046/228] binder: fix UAF of ref->proc caused by race condition commit a0e44c64b6061dda7e00b7c458e4523e2331b739 upstream. A transaction of type BINDER_TYPE_WEAK_HANDLE can fail to increment the reference for a node. In this case, the target proc normally releases the failed reference upon close as expected. However, if the target is dying in parallel the call will race with binder_deferred_release(), so the target could have released all of its references by now leaving the cleanup of the new failed reference unhandled. The transaction then ends and the target proc gets released making the ref->proc now a dangling pointer. Later on, ref->node is closed and we attempt to take spin_lock(&ref->proc->inner_lock), which leads to the use-after-free bug reported below. Let's fix this by cleaning up the failed reference on the spot instead of relying on the target to do so. ================================================================== BUG: KASAN: use-after-free in _raw_spin_lock+0xa8/0x150 Write of size 4 at addr ffff5ca207094238 by task kworker/1:0/590 CPU: 1 PID: 590 Comm: kworker/1:0 Not tainted 5.19.0-rc8 #10 Hardware name: linux,dummy-virt (DT) Workqueue: events binder_deferred_func Call trace: dump_backtrace.part.0+0x1d0/0x1e0 show_stack+0x18/0x70 dump_stack_lvl+0x68/0x84 print_report+0x2e4/0x61c kasan_report+0xa4/0x110 kasan_check_range+0xfc/0x1a4 __kasan_check_write+0x3c/0x50 _raw_spin_lock+0xa8/0x150 binder_deferred_func+0x5e0/0x9b0 process_one_work+0x38c/0x5f0 worker_thread+0x9c/0x694 kthread+0x188/0x190 ret_from_fork+0x10/0x20 Acked-by: Christian Brauner (Microsoft) Signed-off-by: Carlos Llamas Cc: stable # 4.14+ Link: https://lore.kernel.org/r/20220801182511.3371447-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 56a2387656a03..00c6c03ff8222 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1358,6 +1358,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, } ret = binder_inc_ref_olocked(ref, strong, target_list); *rdata = ref->data; + if (ret && ref == new_ref) { + /* + * Cleanup the failed reference here as the target + * could now be dead and have already released its + * references by now. Calling on the new reference + * with strong=0 and a tmp_refs will not decrement + * the node. The new_ref gets kfree'd below. + */ + binder_cleanup_ref_olocked(new_ref); + ref = NULL; + } + binder_proc_unlock(proc); if (new_ref && ref != new_ref) /* From 81203ab7a6ef843a2b904a0a494f28c457d44d27 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 29 Aug 2022 20:12:48 +0000 Subject: [PATCH 047/228] binder: fix alloc->vma_vm_mm null-ptr dereference commit 1da52815d5f1b654c89044db0cdc6adce43da1f1 upstream. Syzbot reported a couple issues introduced by commit 44e602b4e52f ("binder_alloc: add missing mmap_lock calls when using the VMA"), in which we attempt to acquire the mmap_lock when alloc->vma_vm_mm has not been initialized yet. This can happen if a binder_proc receives a transaction without having previously called mmap() to setup the binder_proc->alloc space in [1]. Also, a similar issue occurs via binder_alloc_print_pages() when we try to dump the debugfs binder stats file in [2]. Sample of syzbot's crash report: ================================================================== KASAN: null-ptr-deref in range [0x0000000000000128-0x000000000000012f] CPU: 0 PID: 3755 Comm: syz-executor229 Not tainted 6.0.0-rc1-next-20220819-syzkaller #0 syz-executor229[3755] cmdline: ./syz-executor2294415195 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/22/2022 RIP: 0010:__lock_acquire+0xd83/0x56d0 kernel/locking/lockdep.c:4923 [...] Call Trace: lock_acquire kernel/locking/lockdep.c:5666 [inline] lock_acquire+0x1ab/0x570 kernel/locking/lockdep.c:5631 down_read+0x98/0x450 kernel/locking/rwsem.c:1499 mmap_read_lock include/linux/mmap_lock.h:117 [inline] binder_alloc_new_buf_locked drivers/android/binder_alloc.c:405 [inline] binder_alloc_new_buf+0xa5/0x19e0 drivers/android/binder_alloc.c:593 binder_transaction+0x242e/0x9a80 drivers/android/binder.c:3199 binder_thread_write+0x664/0x3220 drivers/android/binder.c:3986 binder_ioctl_write_read drivers/android/binder.c:5036 [inline] binder_ioctl+0x3470/0x6d00 drivers/android/binder.c:5323 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd [...] ================================================================== Fix these issues by setting up alloc->vma_vm_mm pointer during open() and caching directly from current->mm. This guarantees we have a valid reference to take the mmap_lock during scenarios described above. [1] https://syzkaller.appspot.com/bug?extid=f7dc54e5be28950ac459 [2] https://syzkaller.appspot.com/bug?extid=a75ebe0452711c9e56d9 Fixes: 44e602b4e52f ("binder_alloc: add missing mmap_lock calls when using the VMA") Cc: # v5.15+ Cc: Liam R. Howlett Reported-by: syzbot+f7dc54e5be28950ac459@syzkaller.appspotmail.com Reported-by: syzbot+a75ebe0452711c9e56d9@syzkaller.appspotmail.com Reviewed-by: Liam R. Howlett Acked-by: Todd Kjos Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20220829201254.1814484-2-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index f2d9587833d4b..849f8dff0be1b 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -322,7 +322,6 @@ static inline void binder_alloc_set_vma(struct binder_alloc *alloc, */ if (vma) { vm_start = vma->vm_start; - alloc->vma_vm_mm = vma->vm_mm; mmap_assert_write_locked(alloc->vma_vm_mm); } else { mmap_assert_locked(alloc->vma_vm_mm); @@ -795,7 +794,6 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, binder_insert_free_buffer(alloc, buffer); alloc->free_async_space = alloc->buffer_size / 2; binder_alloc_set_vma(alloc, vma); - mmgrab(alloc->vma_vm_mm); return 0; @@ -1095,6 +1093,8 @@ static struct shrinker binder_shrinker = { void binder_alloc_init(struct binder_alloc *alloc) { alloc->pid = current->group_leader->pid; + alloc->vma_vm_mm = current->mm; + mmgrab(alloc->vma_vm_mm); mutex_init(&alloc->mutex); INIT_LIST_HEAD(&alloc->buffers); } From 9e3c9efa7caf16e5acc05eab5e4d0a714e1610b0 Mon Sep 17 00:00:00 2001 From: Enzo Matsumiya Date: Tue, 30 Aug 2022 19:51:51 -0300 Subject: [PATCH 048/228] cifs: fix small mempool leak in SMB2_negotiate() commit 27893dfc1285f80f80f46b3b8c95f5d15d2e66d0 upstream. In some cases of failure (dialect mismatches) in SMB2_negotiate(), after the request is sent, the checks would return -EIO when they should be rather setting rc = -EIO and jumping to neg_exit to free the response buffer from mempool. Signed-off-by: Enzo Matsumiya Cc: stable@vger.kernel.org Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 49ba3617db593..a423d14035391 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -933,16 +933,17 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) } else if (rc != 0) goto neg_exit; + rc = -EIO; if (strcmp(server->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { cifs_server_dbg(VFS, "SMB2 dialect returned but not requested\n"); - return -EIO; + goto neg_exit; } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { cifs_server_dbg(VFS, "SMB2.1 dialect returned but not requested\n"); - return -EIO; + goto neg_exit; } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { /* ops set to 3.0 by default for default so update */ server->ops = &smb311_operations; @@ -953,7 +954,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { cifs_server_dbg(VFS, "SMB2 dialect returned but not requested\n"); - return -EIO; + goto neg_exit; } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { /* ops set to 3.0 by default for default so update */ server->ops = &smb21_operations; @@ -967,7 +968,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) /* if requested single dialect ensure returned dialect matched */ cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", le16_to_cpu(rsp->DialectRevision)); - return -EIO; + goto neg_exit; } cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode); @@ -985,9 +986,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) else { cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n", le16_to_cpu(rsp->DialectRevision)); - rc = -EIO; goto neg_exit; } + + rc = 0; server->dialect = le16_to_cpu(rsp->DialectRevision); /* From fec48eba4783e326a72c2694e47509354a1d0f16 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Wed, 10 Aug 2022 14:30:50 -0700 Subject: [PATCH 049/228] KVM: VMX: Heed the 'msr' argument in msr_write_intercepted() [ Upstream commit 020dac4187968535f089f83f376a72beb3451311 ] Regardless of the 'msr' argument passed to the VMX version of msr_write_intercepted(), the function always checks to see if a specific MSR (IA32_SPEC_CTRL) is intercepted for write. This behavior seems unintentional and unexpected. Modify the function so that it checks to see if the provided 'msr' index is intercepted for write. Fixes: 67f4b9969c30 ("KVM: nVMX: Handle dynamic MSR intercept toggling") Cc: Sean Christopherson Signed-off-by: Jim Mattson Reviewed-by: Sean Christopherson Message-Id: <20220810213050.2655000-1-jmattson@google.com> Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin --- arch/x86/kvm/vmx/vmx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index cfb3a5c809f2e..e5584e974c774 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -831,8 +831,7 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr) if (!(exec_controls_get(vmx) & CPU_BASED_USE_MSR_BITMAPS)) return true; - return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap, - MSR_IA32_SPEC_CTRL); + return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap, msr); } unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx) From 0522550aeed4ec899d16e237be0ae67f8aa1319b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Aug 2022 13:02:47 +0800 Subject: [PATCH 050/228] drm/i915/reg: Fix spelling mistake "Unsupport" -> "Unsupported" [ Upstream commit 233f56745be446b289edac2ba8184c09365c005e ] There is a spelling mistake in a gvt_vgpu_err error message. Fix it. Fixes: 695fbc08d80f ("drm/i915/gvt: replace the gvt_err with gvt_vgpu_err") Signed-off-by: Colin Ian King Signed-off-by: Zhi Wang Link: http://patchwork.freedesktop.org/patch/msgid/20220315202449.2952845-1-colin.i.king@gmail.com Reviewed-by: Zhi Wang Signed-off-by: Zhenyu Wang Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/gvt/handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index cde0a477fb497..7ed7dba42c834 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -909,7 +909,7 @@ static int update_fdi_rx_iir_status(struct intel_vgpu *vgpu, else if (FDI_RX_IMR_TO_PIPE(offset) != INVALID_INDEX) index = FDI_RX_IMR_TO_PIPE(offset); else { - gvt_vgpu_err("Unsupport registers %x\n", offset); + gvt_vgpu_err("Unsupported registers %x\n", offset); return -EINVAL; } From 519cd9c4b56e2474c1d592110b52bf59eb9d936b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 22 Aug 2022 16:14:23 +0800 Subject: [PATCH 051/228] clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 35b0fac808b95eea1212f8860baf6ad25b88b087 ] In the previous commits that added CLK_OPS_PARENT_ENABLE, support for this flag was only added to rate change operations (rate setting and reparent) and disabling unused subtree. It was not added to the clock gate related operations. Any hardware driver that needs it for these operations will either see bogus results, or worse, hang. This has been seen on MT8192 and MT8195, where the imp_ii2_* clk drivers set this, but dumping debugfs clk_summary would cause it to hang. Fixes: fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)") Fixes: a4b3518d146f ("clk: core: support clocks which requires parents enable (part 1)") Signed-off-by: Chen-Yu Tsai Reviewed-by: Nícolas F. R. A. Prado Tested-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220822081424.1310926-2-wenst@chromium.org Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/clk.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d6dc58bd07b33..973649db3decb 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -203,6 +203,9 @@ static bool clk_core_rate_is_protected(struct clk_core *core) return core->protect_count; } +static int clk_core_prepare_enable(struct clk_core *core); +static void clk_core_disable_unprepare(struct clk_core *core); + static bool clk_core_is_prepared(struct clk_core *core) { bool ret = false; @@ -215,7 +218,11 @@ static bool clk_core_is_prepared(struct clk_core *core) return core->prepare_count; if (!clk_pm_runtime_get(core)) { + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); ret = core->ops->is_prepared(core->hw); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); clk_pm_runtime_put(core); } @@ -251,7 +258,13 @@ static bool clk_core_is_enabled(struct clk_core *core) } } + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); + ret = core->ops->is_enabled(core->hw); + + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); done: if (core->rpm_enabled) pm_runtime_put(core->dev); @@ -818,6 +831,9 @@ int clk_rate_exclusive_get(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_rate_exclusive_get); +static int clk_core_enable_lock(struct clk_core *core); +static void clk_core_disable_lock(struct clk_core *core); + static void clk_core_unprepare(struct clk_core *core) { lockdep_assert_held(&prepare_lock); @@ -841,6 +857,9 @@ static void clk_core_unprepare(struct clk_core *core) WARN(core->enable_count > 0, "Unpreparing enabled %s\n", core->name); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_enable_lock(core->parent); + trace_clk_unprepare(core); if (core->ops->unprepare) @@ -849,6 +868,9 @@ static void clk_core_unprepare(struct clk_core *core) clk_pm_runtime_put(core); trace_clk_unprepare_complete(core); + + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_lock(core->parent); clk_core_unprepare(core->parent); } @@ -897,6 +919,9 @@ static int clk_core_prepare(struct clk_core *core) if (ret) goto runtime_put; + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_enable_lock(core->parent); + trace_clk_prepare(core); if (core->ops->prepare) @@ -904,6 +929,9 @@ static int clk_core_prepare(struct clk_core *core) trace_clk_prepare_complete(core); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_lock(core->parent); + if (ret) goto unprepare; } From c13b0be5ade0acd43110cc13f6b271507e571616 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 31 Aug 2022 10:53:25 -0700 Subject: [PATCH 052/228] Revert "clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops" [ Upstream commit abb5f3f4b1f5f0ad50eb067a00051d3587dec9fb ] This reverts commit 35b0fac808b95eea1212f8860baf6ad25b88b087. Alexander reports that it causes boot failures on i.MX8M Plus based boards (specifically imx8mp-tqma8mpql-mba8mpxl.dts). Reported-by: Alexander Stein Cc: Chen-Yu Tsai Fixes: 35b0fac808b9 ("clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops") Link: https://lore.kernel.org/r/12115951.O9o76ZdvQC@steina-w Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20220831175326.2523912-1-sboyd@kernel.org Signed-off-by: Sasha Levin --- drivers/clk/clk.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 973649db3decb..d6dc58bd07b33 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -203,9 +203,6 @@ static bool clk_core_rate_is_protected(struct clk_core *core) return core->protect_count; } -static int clk_core_prepare_enable(struct clk_core *core); -static void clk_core_disable_unprepare(struct clk_core *core); - static bool clk_core_is_prepared(struct clk_core *core) { bool ret = false; @@ -218,11 +215,7 @@ static bool clk_core_is_prepared(struct clk_core *core) return core->prepare_count; if (!clk_pm_runtime_get(core)) { - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_prepare_enable(core->parent); ret = core->ops->is_prepared(core->hw); - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_unprepare(core->parent); clk_pm_runtime_put(core); } @@ -258,13 +251,7 @@ static bool clk_core_is_enabled(struct clk_core *core) } } - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_prepare_enable(core->parent); - ret = core->ops->is_enabled(core->hw); - - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_unprepare(core->parent); done: if (core->rpm_enabled) pm_runtime_put(core->dev); @@ -831,9 +818,6 @@ int clk_rate_exclusive_get(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_rate_exclusive_get); -static int clk_core_enable_lock(struct clk_core *core); -static void clk_core_disable_lock(struct clk_core *core); - static void clk_core_unprepare(struct clk_core *core) { lockdep_assert_held(&prepare_lock); @@ -857,9 +841,6 @@ static void clk_core_unprepare(struct clk_core *core) WARN(core->enable_count > 0, "Unpreparing enabled %s\n", core->name); - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_enable_lock(core->parent); - trace_clk_unprepare(core); if (core->ops->unprepare) @@ -868,9 +849,6 @@ static void clk_core_unprepare(struct clk_core *core) clk_pm_runtime_put(core); trace_clk_unprepare_complete(core); - - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_lock(core->parent); clk_core_unprepare(core->parent); } @@ -919,9 +897,6 @@ static int clk_core_prepare(struct clk_core *core) if (ret) goto runtime_put; - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_enable_lock(core->parent); - trace_clk_prepare(core); if (core->ops->prepare) @@ -929,9 +904,6 @@ static int clk_core_prepare(struct clk_core *core) trace_clk_prepare_complete(core); - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_lock(core->parent); - if (ret) goto unprepare; } From 9766749a30f6f4425e3d61ce287e0e6eb5e90e25 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 22 Aug 2022 16:14:24 +0800 Subject: [PATCH 053/228] clk: core: Fix runtime PM sequence in clk_core_unprepare() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4b592061f7b3971c70e8b72fc42aaead47c24701 ] In the original commit 9a34b45397e5 ("clk: Add support for runtime PM"), the commit message mentioned that pm_runtime_put_sync() would be done at the end of clk_core_unprepare(). This mirrors the operations in clk_core_prepare() in the opposite order. However, the actual code that was added wasn't in the order the commit message described. Move clk_pm_runtime_put() to the end of clk_core_unprepare() so that it is in the correct order. Fixes: 9a34b45397e5 ("clk: Add support for runtime PM") Signed-off-by: Chen-Yu Tsai Reviewed-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220822081424.1310926-3-wenst@chromium.org Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/clk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d6dc58bd07b33..0674dbc62eb55 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -846,10 +846,9 @@ static void clk_core_unprepare(struct clk_core *core) if (core->ops->unprepare) core->ops->unprepare(core->hw); - clk_pm_runtime_put(core); - trace_clk_unprepare_complete(core); clk_core_unprepare(core->parent); + clk_pm_runtime_put(core); } static void clk_core_unprepare_lock(struct clk_core *core) From 5ba6155d3b2f2d2ba12d961f13ea8987ced18b66 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Mon, 22 Aug 2022 16:33:18 -0700 Subject: [PATCH 054/228] Input: rk805-pwrkey - fix module autoloading [ Upstream commit 99077ad668ddd9b4823cc8ce3f3c7a3fc56f6fd9 ] Add the module alias so the rk805-pwrkey driver will autoload when built as a module. Fixes: 5a35b85c2d92 ("Input: add power key driver for Rockchip RK805 PMIC") Signed-off-by: Peter Robinson Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20220612225437.3628788-1-pbrobinson@gmail.com Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin --- drivers/input/misc/rk805-pwrkey.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/rk805-pwrkey.c b/drivers/input/misc/rk805-pwrkey.c index 3fb64dbda1a21..76873aa005b41 100644 --- a/drivers/input/misc/rk805-pwrkey.c +++ b/drivers/input/misc/rk805-pwrkey.c @@ -98,6 +98,7 @@ static struct platform_driver rk805_pwrkey_driver = { }; module_platform_driver(rk805_pwrkey_driver); +MODULE_ALIAS("platform:rk805-pwrkey"); MODULE_AUTHOR("Joseph Chen "); MODULE_DESCRIPTION("RK805 PMIC Power Key driver"); MODULE_LICENSE("GPL"); From 237b4ef4c08883ea0ae2716ae477b6beb3cc02c5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 25 Jun 2022 10:36:43 +0200 Subject: [PATCH 055/228] clk: bcm: rpi: Fix error handling of raspberrypi_fw_get_rate [ Upstream commit 35f73cca1cecda0c1f8bb7d8be4ce5cd2d46ae8c ] The function raspberrypi_fw_get_rate (e.g. used for the recalc_rate hook) can fail to get the clock rate from the firmware. In this case we cannot return a signed error value, which would be casted to unsigned long. Fix this by returning 0 instead. Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/20220625083643.4012-1-stefan.wahren@i2se.com Fixes: 4e85e535e6cc ("clk: bcm283x: add driver interfacing with Raspberry Pi's firmware") Acked-by: Florian Fainelli Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/bcm/clk-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index dd3b71eafabf3..fda78a2f9ac50 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -139,7 +139,7 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, ret = raspberrypi_clock_property(rpi->firmware, data, RPI_FIRMWARE_GET_CLOCK_RATE, &val); if (ret) - return ret; + return 0; return val; } From e827a5f32a0d2b454335939fb85bf9c72167a6b4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 20 May 2022 23:20:58 +0200 Subject: [PATCH 056/228] clk: bcm: rpi: Use correct order for the parameters of devm_kcalloc() [ Upstream commit b7fa6242f3e035308a76284560e4f918dad9b017 ] We should have 'n', then 'size', not the opposite. This is harmless because the 2 values are just multiplied, but having the correct order silence a (unpublished yet) smatch warning. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/49d726d11964ca0e3757bdb5659e3b3eaa1572b5.1653081643.git.christophe.jaillet@wanadoo.fr Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/bcm/clk-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index fda78a2f9ac50..97612860ce0e1 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -252,7 +252,7 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, int ret; clks = devm_kcalloc(rpi->dev, - sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID, + RPI_FIRMWARE_NUM_CLK_ID, sizeof(*clks), GFP_KERNEL); if (!clks) return -ENOMEM; From ff0b144d4b0a9fbd6efe4d2c0a4b6c9bae2138d2 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 13 Jul 2022 17:49:51 +0200 Subject: [PATCH 057/228] clk: bcm: rpi: Prevent out-of-bounds access [ Upstream commit bc163555603e4ae9c817675ad80d618a4cdbfa2d ] The while loop in raspberrypi_discover_clocks() relies on the assumption that the id of the last clock element is zero. Because this data comes from the Videocore firmware and it doesn't guarantuee such a behavior this could lead to out-of-bounds access. So fix this by providing a sentinel element. Fixes: 93d2725affd6 ("clk: bcm: rpi: Discover the firmware clocks") Link: https://github.com/raspberrypi/firmware/issues/1688 Suggested-by: Phil Elwell Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/20220713154953.3336-2-stefan.wahren@i2se.com Acked-by: Florian Fainelli Reviewed-by: Ivan T. Ivanov Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/bcm/clk-raspberrypi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 97612860ce0e1..834bcc256e921 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -251,8 +251,13 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, struct rpi_firmware_get_clocks_response *clks; int ret; + /* + * The firmware doesn't guarantee that the last element of + * RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional + * zero element as sentinel. + */ clks = devm_kcalloc(rpi->dev, - RPI_FIRMWARE_NUM_CLK_ID, sizeof(*clks), + RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks), GFP_KERNEL); if (!clks) return -ENOMEM; From 7b8a284ffe7a9f2d5b8386940845fde82690b8d2 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 13 Jul 2022 17:49:52 +0200 Subject: [PATCH 058/228] clk: bcm: rpi: Add missing newline [ Upstream commit 13b5cf8d6a0d4a5d289e1ed046cadc63b416db85 ] Some log messages lacks the final newline. So add them. Fixes: 93d2725affd6 ("clk: bcm: rpi: Discover the firmware clocks") Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/20220713154953.3336-3-stefan.wahren@i2se.com Acked-by: Florian Fainelli Reviewed-by: Ivan T. Ivanov Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/bcm/clk-raspberrypi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 834bcc256e921..56c5166f841ae 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -156,7 +156,7 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, ret = raspberrypi_clock_property(rpi->firmware, data, RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); if (ret) - dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", + dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n", clk_hw_get_name(hw), ret); return ret; @@ -208,7 +208,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, RPI_FIRMWARE_GET_MIN_CLOCK_RATE, &min_rate); if (ret) { - dev_err(rpi->dev, "Failed to get clock %d min freq: %d", + dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n", id, ret); return ERR_PTR(ret); } From 53196e0376205ed49b75bfd0475af5e0fbd20156 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 30 Aug 2022 03:11:01 +0200 Subject: [PATCH 059/228] hwmon: (gpio-fan) Fix array out of bounds access [ Upstream commit f233d2be38dbbb22299192292983037f01ab363c ] The driver does not check if the cooling state passed to gpio_fan_set_cur_state() exceeds the maximum cooling state as stored in fan_data->num_speeds. Since the cooling state is later used as an array index in set_fan_speed(), an array out of bounds access can occur. This can be exploited by setting the state of the thermal cooling device to arbitrary values, causing for example a kernel oops when unavailable memory is accessed this way. Example kernel oops: [ 807.987276] Unable to handle kernel paging request at virtual address ffffff80d0588064 [ 807.987369] Mem abort info: [ 807.987398] ESR = 0x96000005 [ 807.987428] EC = 0x25: DABT (current EL), IL = 32 bits [ 807.987477] SET = 0, FnV = 0 [ 807.987507] EA = 0, S1PTW = 0 [ 807.987536] FSC = 0x05: level 1 translation fault [ 807.987570] Data abort info: [ 807.987763] ISV = 0, ISS = 0x00000005 [ 807.987801] CM = 0, WnR = 0 [ 807.987832] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000001165000 [ 807.987872] [ffffff80d0588064] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 [ 807.987961] Internal error: Oops: 96000005 [#1] PREEMPT SMP [ 807.987992] Modules linked in: cmac algif_hash aes_arm64 algif_skcipher af_alg bnep hci_uart btbcm bluetooth ecdh_generic ecc 8021q garp stp llc snd_soc_hdmi_codec brcmfmac vc4 brcmutil cec drm_kms_helper snd_soc_core cfg80211 snd_compress bcm2835_codec(C) snd_pcm_dmaengine syscopyarea bcm2835_isp(C) bcm2835_v4l2(C) sysfillrect v4l2_mem2mem bcm2835_mmal_vchiq(C) raspberrypi_hwmon sysimgblt videobuf2_dma_contig videobuf2_vmalloc fb_sys_fops videobuf2_memops rfkill videobuf2_v4l2 videobuf2_common i2c_bcm2835 snd_bcm2835(C) videodev snd_pcm snd_timer snd mc vc_sm_cma(C) gpio_fan uio_pdrv_genirq uio drm fuse drm_panel_orientation_quirks backlight ip_tables x_tables ipv6 [ 807.988508] CPU: 0 PID: 1321 Comm: bash Tainted: G C 5.15.56-v8+ #1575 [ 807.988548] Hardware name: Raspberry Pi 3 Model B Rev 1.2 (DT) [ 807.988574] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 807.988608] pc : set_fan_speed.part.5+0x34/0x80 [gpio_fan] [ 807.988654] lr : gpio_fan_set_cur_state+0x34/0x50 [gpio_fan] [ 807.988691] sp : ffffffc008cf3bd0 [ 807.988710] x29: ffffffc008cf3bd0 x28: ffffff80019edac0 x27: 0000000000000000 [ 807.988762] x26: 0000000000000000 x25: 0000000000000000 x24: ffffff800747c920 [ 807.988787] x23: 000000000000000a x22: ffffff800369f000 x21: 000000001999997c [ 807.988854] x20: ffffff800369f2e8 x19: ffffff8002ae8080 x18: 0000000000000000 [ 807.988877] x17: 0000000000000000 x16: 0000000000000000 x15: 000000559e271b70 [ 807.988938] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 807.988960] x11: 0000000000000000 x10: ffffffc008cf3c20 x9 : ffffffcfb60c741c [ 807.989018] x8 : 000000000000000a x7 : 00000000ffffffc9 x6 : 0000000000000009 [ 807.989040] x5 : 000000000000002a x4 : 0000000000000000 x3 : ffffff800369f2e8 [ 807.989062] x2 : 000000000000e780 x1 : 0000000000000001 x0 : ffffff80d0588060 [ 807.989084] Call trace: [ 807.989091] set_fan_speed.part.5+0x34/0x80 [gpio_fan] [ 807.989113] gpio_fan_set_cur_state+0x34/0x50 [gpio_fan] [ 807.989199] cur_state_store+0x84/0xd0 [ 807.989221] dev_attr_store+0x20/0x38 [ 807.989262] sysfs_kf_write+0x4c/0x60 [ 807.989282] kernfs_fop_write_iter+0x130/0x1c0 [ 807.989298] new_sync_write+0x10c/0x190 [ 807.989315] vfs_write+0x254/0x378 [ 807.989362] ksys_write+0x70/0xf8 [ 807.989379] __arm64_sys_write+0x24/0x30 [ 807.989424] invoke_syscall+0x4c/0x110 [ 807.989442] el0_svc_common.constprop.3+0xfc/0x120 [ 807.989458] do_el0_svc+0x2c/0x90 [ 807.989473] el0_svc+0x24/0x60 [ 807.989544] el0t_64_sync_handler+0x90/0xb8 [ 807.989558] el0t_64_sync+0x1a0/0x1a4 [ 807.989579] Code: b9403801 f9402800 7100003f 8b35cc00 (b9400416) [ 807.989627] ---[ end trace 8ded4c918658445b ]--- Fix this by checking the cooling state and return an error if it exceeds the maximum cooling state. Tested on a Raspberry Pi 3. Fixes: b5cf88e46bad ("(gpio-fan): Add thermal control hooks") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20220830011101.178843-1-W_Armin@gmx.de Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/gpio-fan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index befe989ca7b94..fbf3f5a4ecb67 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -391,6 +391,9 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, if (!fan_data) return -EINVAL; + if (state >= fan_data->num_speed) + return -EINVAL; + set_fan_speed(fan_data, state); return 0; } From 111a3586ed4a6ee15e467e58c9208152d469f430 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 31 Aug 2022 18:37:35 +0800 Subject: [PATCH 060/228] gpio: pca953x: Add mutex_lock for regcache sync in PM [ Upstream commit 518e26f11af2fe4f5bebf9a0351595d508c7077f ] The regcache sync will set the cache_bypass = true, at that time, when there is regmap write operation, it will bypass the regmap cache, then the regcache sync will write back the value from cache to register, which is not as our expectation. Though regmap already use its internal lock to avoid such issue, but this driver force disable the regmap internal lock in its regmap config: disable_locking = true To avoid this issue, use the driver's own lock to do the protect in system PM. Fixes: b76574300504 ("gpio: pca953x: Restore registers after suspend/resume cycle") Signed-off-by: Haibo Chen Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/gpio-pca953x.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 64befd6f702b2..4860bf3b7e002 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1163,7 +1163,9 @@ static int pca953x_suspend(struct device *dev) { struct pca953x_chip *chip = dev_get_drvdata(dev); + mutex_lock(&chip->i2c_lock); regcache_cache_only(chip->regmap, true); + mutex_unlock(&chip->i2c_lock); if (atomic_read(&chip->wakeup_path)) device_set_wakeup_path(dev); @@ -1186,13 +1188,17 @@ static int pca953x_resume(struct device *dev) } } + mutex_lock(&chip->i2c_lock); regcache_cache_only(chip->regmap, false); regcache_mark_dirty(chip->regmap); ret = pca953x_regcache_sync(dev); - if (ret) + if (ret) { + mutex_unlock(&chip->i2c_lock); return ret; + } ret = regcache_sync(chip->regmap); + mutex_unlock(&chip->i2c_lock); if (ret) { dev_err(dev, "Failed to restore register map: %d\n", ret); return ret; From 03b1870fbc5e2488370ceccc0e346e71f07dc9d0 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 30 Aug 2022 10:49:47 -0700 Subject: [PATCH 061/228] KVM: x86: Mask off unsupported and unknown bits of IA32_ARCH_CAPABILITIES [ Upstream commit 0204750bd4c6ccc2fb7417618477f10373b33f56 ] KVM should not claim to virtualize unknown IA32_ARCH_CAPABILITIES bits. When kvm_get_arch_capabilities() was originally written, there were only a few bits defined in this MSR, and KVM could virtualize all of them. However, over the years, several bits have been defined that KVM cannot just blindly pass through to the guest without additional work (such as virtualizing an MSR promised by the IA32_ARCH_CAPABILITES feature bit). Define a mask of supported IA32_ARCH_CAPABILITIES bits, and mask off any other bits that are set in the hardware MSR. Cc: Paolo Bonzini Fixes: 5b76a3cff011 ("KVM: VMX: Tell the nested hypervisor to skip L1D flush on vmentry") Signed-off-by: Jim Mattson Reviewed-by: Vipin Sharma Reviewed-by: Xiaoyao Li Message-Id: <20220830174947.2182144-1-jmattson@google.com> Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin --- arch/x86/kvm/x86.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f5b7a05530eb0..9109e5589b421 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1465,12 +1465,32 @@ static const u32 msr_based_features_all[] = { static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all)]; static unsigned int num_msr_based_features; +/* + * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM + * does not yet virtualize. These include: + * 10 - MISC_PACKAGE_CTRLS + * 11 - ENERGY_FILTERING_CTL + * 12 - DOITM + * 18 - FB_CLEAR_CTRL + * 21 - XAPIC_DISABLE_STATUS + * 23 - OVERCLOCKING_STATUS + */ + +#define KVM_SUPPORTED_ARCH_CAP \ + (ARCH_CAP_RDCL_NO | ARCH_CAP_IBRS_ALL | ARCH_CAP_RSBA | \ + 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) + static u64 kvm_get_arch_capabilities(void) { u64 data = 0; - if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) + if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data); + data &= KVM_SUPPORTED_ARCH_CAP; + } /* * If nx_huge_pages is enabled, KVM's shadow paging will ensure that @@ -1518,9 +1538,6 @@ static u64 kvm_get_arch_capabilities(void) */ } - /* Guests don't need to know "Fill buffer clear control" exists */ - data &= ~ARCH_CAP_FB_CLEAR_CTRL; - return data; } From 763d77241d8fc79225a939a3512a5b986d4c9aae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 1 Sep 2022 18:35:20 +0300 Subject: [PATCH 062/228] xen/grants: prevent integer overflow in gnttab_dma_alloc_pages() [ Upstream commit e9ea0b30ada008f4e65933f449db6894832cb242 ] The change from kcalloc() to kvmalloc() means that arg->nr_pages might now be large enough that the "args->nr_pages << PAGE_SHIFT" can result in an integer overflow. Fixes: b3f7931f5c61 ("xen/gntdev: switch from kcalloc() to kvcalloc()") Signed-off-by: Dan Carpenter Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/YxDROJqu/RPvR0bi@kili Signed-off-by: Juergen Gross Signed-off-by: Sasha Levin --- drivers/xen/grant-table.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 5c83d41766c85..0a2d24d6ac6f7 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -981,6 +981,9 @@ int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args) size_t size; int i, ret; + if (args->nr_pages < 0 || args->nr_pages > (INT_MAX >> PAGE_SHIFT)) + return -ENOMEM; + size = args->nr_pages << PAGE_SHIFT; if (args->coherent) args->vaddr = dma_alloc_coherent(args->dev, size, From c235c4fc521f439c4929932bd88f7e018af7055d Mon Sep 17 00:00:00 2001 From: Steven Price Date: Fri, 2 Sep 2022 12:26:12 +0100 Subject: [PATCH 063/228] mm: pagewalk: Fix race between unmap and page walker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8782fb61cc848364e1e1599d76d3c9dd58a1cc06 ] The mmap lock protects the page walker from changes to the page tables during the walk. However a read lock is insufficient to protect those areas which don't have a VMA as munmap() detaches the VMAs before downgrading to a read lock and actually tearing down PTEs/page tables. For users of walk_page_range() the solution is to simply call pte_hole() immediately without checking the actual page tables when a VMA is not present. We now never call __walk_page_range() without a valid vma. For walk_page_range_novma() the locking requirements are tightened to require the mmap write lock to be taken, and then walking the pgd directly with 'no_vma' set. This in turn means that all page walkers either have a valid vma, or it's that special 'novma' case for page table debugging. As a result, all the odd '(!walk->vma && !walk->no_vma)' tests can be removed. Fixes: dd2283f2605e ("mm: mmap: zap pages with read mmap_sem in munmap") Reported-by: Jann Horn Signed-off-by: Steven Price Cc: Vlastimil Babka Cc: Thomas Hellström Cc: Konstantin Khlebnikov Cc: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- arch/riscv/mm/pageattr.c | 4 ++-- mm/pagewalk.c | 21 ++++++++++++--------- mm/ptdump.c | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index 5e49e4b4a4ccc..86c56616e5dea 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -118,10 +118,10 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, if (!numpages) return 0; - mmap_read_lock(&init_mm); + mmap_write_lock(&init_mm); ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, &masks); - mmap_read_unlock(&init_mm); + mmap_write_unlock(&init_mm); flush_tlb_kernel_range(start, end); diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 9b3db11a4d1db..fa7a3d21a7518 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -110,7 +110,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, do { again: next = pmd_addr_end(addr, end); - if (pmd_none(*pmd) || (!walk->vma && !walk->no_vma)) { + if (pmd_none(*pmd)) { if (ops->pte_hole) err = ops->pte_hole(addr, next, depth, walk); if (err) @@ -171,7 +171,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, do { again: next = pud_addr_end(addr, end); - if (pud_none(*pud) || (!walk->vma && !walk->no_vma)) { + if (pud_none(*pud)) { if (ops->pte_hole) err = ops->pte_hole(addr, next, depth, walk); if (err) @@ -366,19 +366,19 @@ static int __walk_page_range(unsigned long start, unsigned long end, struct vm_area_struct *vma = walk->vma; const struct mm_walk_ops *ops = walk->ops; - if (vma && ops->pre_vma) { + if (ops->pre_vma) { err = ops->pre_vma(start, end, walk); if (err) return err; } - if (vma && is_vm_hugetlb_page(vma)) { + if (is_vm_hugetlb_page(vma)) { if (ops->hugetlb_entry) err = walk_hugetlb_range(start, end, walk); } else err = walk_pgd_range(start, end, walk); - if (vma && ops->post_vma) + if (ops->post_vma) ops->post_vma(walk); return err; @@ -450,9 +450,13 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, if (!vma) { /* after the last vma */ walk.vma = NULL; next = end; + if (ops->pte_hole) + err = ops->pte_hole(start, next, -1, &walk); } else if (start < vma->vm_start) { /* outside vma */ walk.vma = NULL; next = min(end, vma->vm_start); + if (ops->pte_hole) + err = ops->pte_hole(start, next, -1, &walk); } else { /* inside vma */ walk.vma = vma; next = min(end, vma->vm_end); @@ -470,9 +474,8 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, } if (err < 0) break; - } - if (walk.vma || walk.ops->pte_hole) err = __walk_page_range(start, next, &walk); + } if (err) break; } while (start = next, start < end); @@ -501,9 +504,9 @@ int walk_page_range_novma(struct mm_struct *mm, unsigned long start, if (start >= end || !walk.mm) return -EINVAL; - mmap_assert_locked(walk.mm); + mmap_assert_write_locked(walk.mm); - return __walk_page_range(start, end, &walk); + return walk_pgd_range(start, end, &walk); } int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops, diff --git a/mm/ptdump.c b/mm/ptdump.c index da751448d0e4e..f84ea700662fc 100644 --- a/mm/ptdump.c +++ b/mm/ptdump.c @@ -144,13 +144,13 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd) { const struct ptdump_range *range = st->range; - mmap_read_lock(mm); + mmap_write_lock(mm); while (range->start != range->end) { walk_page_range_novma(mm, range->start, range->end, &ptdump_ops, pgd, st); range++; } - mmap_read_unlock(mm); + mmap_write_unlock(mm); /* Flush out the last page */ st->note_page(st, 0, -1, 0); From 3e8107d69fc32e675a6559968c35f3fdecac5f8c Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 31 Aug 2022 16:58:22 +0000 Subject: [PATCH 064/228] xen-blkback: Advertise feature-persistent as user requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 06ba5d2e943e97bb66e75c152e87f1d2c7027a67 upstream. The advertisement of the persistent grants feature (writing 'feature-persistent' to xenbus) should mean not the decision for using the feature but only the availability of the feature. However, commit aac8a70db24b ("xen-blkback: add a parameter for disabling of persistent grants") made a field of blkback, which was a place for saving only the negotiation result, to be used for yet another purpose: caching of the 'feature_persistent' parameter value. As a result, the advertisement, which should follow only the parameter value, becomes inconsistent. This commit fixes the misuse of the semantic by making blkback saves the parameter value in a separate place and advertises the support based on only the saved value. Fixes: aac8a70db24b ("xen-blkback: add a parameter for disabling of persistent grants") Cc: # 5.10.x Suggested-by: Juergen Gross Signed-off-by: SeongJae Park Tested-by: Marek Marczykowski-Górecki Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20220831165824.94815-2-sj@kernel.org Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkback/common.h | 3 +++ drivers/block/xen-blkback/xenbus.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index bda5c815e4415..a28473470e662 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -226,6 +226,9 @@ struct xen_vbd { sector_t size; unsigned int flush_support:1; unsigned int discard_secure:1; + /* Connect-time cached feature_persistent parameter value */ + unsigned int feature_gnt_persistent_parm:1; + /* Persistent grants feature negotiation result */ unsigned int feature_gnt_persistent:1; unsigned int overflow_max_grants:1; }; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 78b50ac11e191..1525e28c5d703 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -910,7 +910,7 @@ static void connect(struct backend_info *be) xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", - be->blkif->vbd.feature_gnt_persistent); + be->blkif->vbd.feature_gnt_persistent_parm); if (err) { xenbus_dev_fatal(dev, err, "writing %s/feature-persistent", dev->nodename); @@ -1088,7 +1088,9 @@ static int connect_ring(struct backend_info *be) return -ENOSYS; } - blkif->vbd.feature_gnt_persistent = feature_persistent && + blkif->vbd.feature_gnt_persistent_parm = feature_persistent; + blkif->vbd.feature_gnt_persistent = + blkif->vbd.feature_gnt_persistent_parm && xenbus_read_unsigned(dev->otherend, "feature-persistent", 0); blkif->vbd.overflow_max_grants = 0; From 895a90ad7b3ee1df3fb58260b63d3192feb60d11 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 31 Aug 2022 16:58:23 +0000 Subject: [PATCH 065/228] xen-blkfront: Advertise feature-persistent as user requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9f5e0fe5d05f7e8de7f39b2b10089834eb0ff787 upstream. The advertisement of the persistent grants feature (writing 'feature-persistent' to xenbus) should mean not the decision for using the feature but only the availability of the feature. However, commit 74a852479c68 ("xen-blkfront: add a parameter for disabling of persistent grants") made a field of blkfront, which was a place for saving only the negotiation result, to be used for yet another purpose: caching of the 'feature_persistent' parameter value. As a result, the advertisement, which should follow only the parameter value, becomes inconsistent. This commit fixes the misuse of the semantic by making blkfront saves the parameter value in a separate place and advertises the support based on only the saved value. Fixes: 74a852479c68 ("xen-blkfront: add a parameter for disabling of persistent grants") Cc: # 5.10.x Suggested-by: Juergen Gross Signed-off-by: SeongJae Park Tested-by: Marek Marczykowski-Górecki Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20220831165824.94815-3-sj@kernel.org Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkfront.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 23fc4c8f26039..762272e217a23 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -212,6 +212,9 @@ struct blkfront_info unsigned int feature_fua:1; unsigned int feature_discard:1; unsigned int feature_secdiscard:1; + /* Connect-time cached feature_persistent parameter */ + unsigned int feature_persistent_parm:1; + /* Persistent grants feature negotiation result */ unsigned int feature_persistent:1; unsigned int bounce:1; unsigned int discard_granularity; @@ -1874,7 +1877,7 @@ static int talk_to_blkback(struct xenbus_device *dev, goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", - info->feature_persistent); + info->feature_persistent_parm); if (err) dev_warn(&dev->dev, "writing persistent grants feature to xenbus"); @@ -2307,7 +2310,8 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) if (xenbus_read_unsigned(info->xbdev->otherend, "feature-discard", 0)) blkfront_setup_discard(info); - if (feature_persistent) + info->feature_persistent_parm = feature_persistent; + if (info->feature_persistent_parm) info->feature_persistent = !!xenbus_read_unsigned(info->xbdev->otherend, "feature-persistent", 0); From e31db376f6d1863c76eb1c81191b0845607720e4 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 31 Aug 2022 16:58:24 +0000 Subject: [PATCH 066/228] xen-blkfront: Cache feature_persistent value before advertisement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fe8f65b018effbf473f53af3538d0c1878b8b329 upstream. Xen blkfront advertises its support of the persistent grants feature when it first setting up and when resuming in 'talk_to_blkback()'. Then, blkback reads the advertised value when it connects with blkfront and decides if it will use the persistent grants feature or not, and advertises its decision to blkfront. Blkfront reads the blkback's decision and it also makes the decision for the use of the feature. Commit 402c43ea6b34 ("xen-blkfront: Apply 'feature_persistent' parameter when connect"), however, made the blkfront's read of the parameter for disabling the advertisement, namely 'feature_persistent', to be done when it negotiate, not when advertise. Therefore blkfront advertises without reading the parameter. As the field for caching the parameter value is zero-initialized, it always advertises as the feature is disabled, so that the persistent grants feature becomes always disabled. This commit fixes the issue by making the blkfront does parmeter caching just before the advertisement. Fixes: 402c43ea6b34 ("xen-blkfront: Apply 'feature_persistent' parameter when connect") Cc: # 5.10.x Reported-by: Marek Marczykowski-Górecki Signed-off-by: SeongJae Park Tested-by: Marek Marczykowski-Górecki Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20220831165824.94815-4-sj@kernel.org Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkfront.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 762272e217a23..24a86d829f92a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1785,6 +1785,12 @@ static int write_per_ring_nodes(struct xenbus_transaction xbt, return err; } +/* Enable the persistent grants feature. */ +static bool feature_persistent = true; +module_param(feature_persistent, bool, 0644); +MODULE_PARM_DESC(feature_persistent, + "Enables the persistent grants feature"); + /* Common code used when first setting up, and when resuming. */ static int talk_to_blkback(struct xenbus_device *dev, struct blkfront_info *info) @@ -1876,6 +1882,7 @@ static int talk_to_blkback(struct xenbus_device *dev, message = "writing protocol"; goto abort_transaction; } + info->feature_persistent_parm = feature_persistent; err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", info->feature_persistent_parm); if (err) @@ -1945,12 +1952,6 @@ static int negotiate_mq(struct blkfront_info *info) return 0; } -/* Enable the persistent grants feature. */ -static bool feature_persistent = true; -module_param(feature_persistent, bool, 0644); -MODULE_PARM_DESC(feature_persistent, - "Enables the persistent grants feature"); - /* * Entry point to this code when a new device is created. Allocate the basic * structures and the ring buffer for communication with the backend, and @@ -2310,7 +2311,6 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) if (xenbus_read_unsigned(info->xbdev->otherend, "feature-discard", 0)) blkfront_setup_discard(info); - info->feature_persistent_parm = feature_persistent; if (info->feature_persistent_parm) info->feature_persistent = !!xenbus_read_unsigned(info->xbdev->otherend, From 23987d01de44507f2e322dcfc154fd64f2238927 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 29 Apr 2022 17:10:17 +0300 Subject: [PATCH 067/228] thunderbolt: Use the actual buffer in tb_async_error() commit eb100b8fa8e8b59eb3e5fc7a5fd4a1e3c5950f64 upstream. The received notification packet is held in pkg->buffer and not in pkg itself. Fix this by using the correct buffer. Fixes: 81a54b5e1986 ("thunderbolt: Let the connection manager handle all notifications") Cc: stable@vger.kernel.org Signed-off-by: Mika Westerberg Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 0fb5e04191e24..409ee1551a7cf 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -408,7 +408,7 @@ static void tb_ctl_rx_submit(struct ctl_pkg *pkg) static int tb_async_error(const struct ctl_pkg *pkg) { - const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg; + const struct cfg_error_pkg *error = pkg->buffer; if (pkg->frame.eof != TB_CFG_PKG_ERROR) return false; From 2c948dd68b9e218d6b18732cf3b1664a54fcf10c Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 15 Aug 2022 15:33:34 +0300 Subject: [PATCH 068/228] usb: dwc3: pci: Add support for Intel Raptor Lake commit bad0d1d726ace2db9e0f39c62b173bc7cc43dd6a upstream. This adds the necessary PCI device ID for the controller inside the Intel Raptor Lake CPU block. The controllers that are part of the PCH (chipset) have separate device IDs. Cc: stable@vger.kernel.org Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220815123334.87526-1-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 9c8887615701f..c52f7b5b5ec00 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -43,6 +43,7 @@ #define PCI_DEVICE_ID_INTEL_ADLP 0x51ee #define PCI_DEVICE_ID_INTEL_ADLM 0x54ee #define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1 +#define PCI_DEVICE_ID_INTEL_RPL 0x460e #define PCI_DEVICE_ID_INTEL_RPLS 0x7a61 #define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1 #define PCI_DEVICE_ID_INTEL_MTL 0x7e7e @@ -420,6 +421,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, From 75913c562f5ba4cf397d835c63f443879167c6f6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 26 Aug 2022 15:31:40 -0400 Subject: [PATCH 069/228] media: mceusb: Use new usb_control_msg_*() routines commit 608e58a0f4617977178131f5f68a3fce1d3f5316 upstream. Automatic kernel fuzzing led to a WARN about invalid pipe direction in the mceusb driver: ------------[ cut here ]------------ usb 6-1: BOGUS control dir, pipe 80000380 doesn't match bRequestType 40 WARNING: CPU: 0 PID: 2465 at drivers/usb/core/urb.c:410 usb_submit_urb+0x1326/0x1820 drivers/usb/core/urb.c:410 Modules linked in: CPU: 0 PID: 2465 Comm: kworker/0:2 Not tainted 5.19.0-rc4-00208-g69cb6c6556ad #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Workqueue: usb_hub_wq hub_event RIP: 0010:usb_submit_urb+0x1326/0x1820 drivers/usb/core/urb.c:410 Code: 7c 24 40 e8 ac 23 91 fd 48 8b 7c 24 40 e8 b2 70 1b ff 45 89 e8 44 89 f1 4c 89 e2 48 89 c6 48 c7 c7 a0 30 a9 86 e8 48 07 11 02 <0f> 0b e9 1c f0 ff ff e8 7e 23 91 fd 0f b6 1d 63 22 83 05 31 ff 41 RSP: 0018:ffffc900032becf0 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff8881100f3058 RCX: 0000000000000000 RDX: ffffc90004961000 RSI: ffff888114c6d580 RDI: fffff52000657d90 RBP: ffff888105ad90f0 R08: ffffffff812c3638 R09: 0000000000000000 R10: 0000000000000005 R11: ffffed1023504ef1 R12: ffff888105ad9000 R13: 0000000000000040 R14: 0000000080000380 R15: ffff88810ba96500 FS: 0000000000000000(0000) GS:ffff88811a800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ffe810bda58 CR3: 000000010b720000 CR4: 0000000000350ef0 Call Trace: usb_start_wait_urb+0x101/0x4c0 drivers/usb/core/message.c:58 usb_internal_control_msg drivers/usb/core/message.c:102 [inline] usb_control_msg+0x31c/0x4a0 drivers/usb/core/message.c:153 mceusb_gen1_init drivers/media/rc/mceusb.c:1431 [inline] mceusb_dev_probe+0x258e/0x33f0 drivers/media/rc/mceusb.c:1807 The reason for the warning is clear enough; the driver sends an unusual read request on endpoint 0 but does not set the USB_DIR_IN bit in the bRequestType field. More importantly, the whole situation can be avoided and the driver simplified by converting it over to the relatively new usb_control_msg_recv() and usb_control_msg_send() routines. That's what this fix does. Link: https://lore.kernel.org/all/CAB7eexLLApHJwZfMQ=X-PtRhw0BgO+5KcSMS05FNUYejJXqtSA@mail.gmail.com/ Cc: Mauro Carvalho Chehab Cc: stable@vger.kernel.org Reported-and-tested-by: Rondreis Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/YwkfnBFCSEVC6XZu@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/mceusb.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5f296f985b07a..deb3db45a94ce 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1416,42 +1416,37 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) { int ret; struct device *dev = ir->dev; - char *data; - - data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s: memory allocation failed!", __func__); - return; - } + char data[USB_CTRL_MSG_SZ]; /* * This is a strange one. Windows issues a set address to the device * on the receive control pipe and expect a certain value pair back */ - ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, - data, USB_CTRL_MSG_SZ, 3000); + ret = usb_control_msg_recv(ir->usbdev, 0, USB_REQ_SET_ADDRESS, + USB_DIR_IN | USB_TYPE_VENDOR, + 0, 0, data, USB_CTRL_MSG_SZ, 3000, + GFP_KERNEL); dev_dbg(dev, "set address - ret = %d", ret); dev_dbg(dev, "set address - data[0] = %d, data[1] = %d", data[0], data[1]); /* set feature: bit rate 38400 bps */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, - 0xc04e, 0x0000, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, + 0xc04e, 0x0000, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set feature - ret = %d", ret); /* bRequest 4: set char length to 8 bits */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 4, USB_TYPE_VENDOR, - 0x0808, 0x0000, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + 4, USB_TYPE_VENDOR, + 0x0808, 0x0000, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set char length - retB = %d", ret); /* bRequest 2: set handshaking to use DTR/DSR */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 2, USB_TYPE_VENDOR, - 0x0000, 0x0100, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + 2, USB_TYPE_VENDOR, + 0x0000, 0x0100, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set handshake - retC = %d", ret); /* device resume */ @@ -1459,8 +1454,6 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) /* get hw/sw revision? */ mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION)); - - kfree(data); } static void mceusb_gen2_init(struct mceusb_dev *ir) From 3a6c5c5ab734dbe27bd4dede6def79c24154d049 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 25 Aug 2022 18:08:39 +0300 Subject: [PATCH 070/228] xhci: Add grace period after xHC start to prevent premature runtime suspend. commit 33e321586e37b642ad10594b9ef25a613555cd08 upstream. After xHC controller is started, either in probe or resume, it can take a while before any of the connected usb devices are visible to the roothub due to link training. It's possible xhci driver loads, sees no acivity and suspends the host before the USB device is visible. In one testcase with a hotplugged xHC controller the host finally detected the connected USB device and generated a wake 500ms after host initial start. If hosts didn't suspend the device duringe training it probablty wouldn't take up to 500ms to detect it, but looking at specs reveal USB3 link training has a couple long timeout values, such as 120ms RxDetectQuietTimeout, and 360ms PollingLFPSTimeout. So Add a 500ms grace period that keeps polling the roothub for 500ms after start, preventing runtime suspend until USB devices are detected. Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20220825150840.132216-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 11 +++++++++++ drivers/usb/host/xhci.c | 4 +++- drivers/usb/host/xhci.h | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index f65f1ba2b5929..b9754784161d7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1647,6 +1647,17 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) status = bus_state->resuming_ports; + /* + * SS devices are only visible to roothub after link training completes. + * Keep polling roothubs for a grace period after xHC start + */ + if (xhci->run_graceperiod) { + if (time_before(jiffies, xhci->run_graceperiod)) + status = 1; + else + xhci->run_graceperiod = 0; + } + mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; /* For each port, did anything change? If so, set that bit in buf. */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e3767651c9a9e..3cac7e40456eb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -148,9 +148,11 @@ int xhci_start(struct xhci_hcd *xhci) xhci_err(xhci, "Host took too long to start, " "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); - if (!ret) + if (!ret) { /* clear state flags. Including dying, halted or removing */ xhci->xhc_state = 0; + xhci->run_graceperiod = jiffies + msecs_to_jiffies(500); + } return ret; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 81e1bfdf83988..10a4230d95c37 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1830,7 +1830,7 @@ struct xhci_hcd { /* Host controller watchdog timer structures */ unsigned int xhc_state; - + unsigned long run_graceperiod; u32 command; struct s3_save s3; /* Host controller is dying - not responding to commands. "I'm not dead yet!" From 2bb1ad8c957df3b53ff7bef6f25cf698626c23a3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 29 Aug 2022 16:25:50 +0200 Subject: [PATCH 071/228] USB: serial: cp210x: add Decagon UCA device id commit ceb4038472a4803e7046ed488b03d11551991514 upstream. Add the device id for Decagon Devices USB Cable Adapter. Link: https://lore.kernel.org/r/trinity-819f9db2-d3e1-40e9-a669-9c245817c046-1661523546680@msvc-mesg-web108 Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index bd006e1712ccb..a2126b07e854a 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -130,6 +130,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */ { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8414) }, /* Decagon USB Cable Adapter */ { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ From 93c283a0995942d2b3cda7d7e44a6f13b3b52572 Mon Sep 17 00:00:00 2001 From: Yan Xinyu Date: Thu, 14 Jul 2022 18:20:37 +0800 Subject: [PATCH 072/228] USB: serial: option: add support for OPPO R11 diag port commit 8d5fc280392735e4441b35de14f2f4860fa8d83c upstream. Add support for OPPO R11 USB diag serial port to option driver. This phone uses Qualcomm Snapdragon 660 SoC. usb-devices output: T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=22d9 ProdID=276c Rev=04.04 S: Manufacturer=OPPO S: Product=SDM660-MTP _SN:09C6BCA7 S: SerialNumber=beb2c403 C: #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=500mA I: If#=0x0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option I: If#=0x1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs Signed-off-by: Yan Xinyu Link: https://lore.kernel.org/r/20220714102037.4113889-1-sdlyyxy@bupt.edu.cn Link: https://lore.kernel.org/r/Yt1WfSZk03Plpnan@hovoldconsulting.com Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index de59fa919540a..cf65cb84c3cae 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -573,6 +573,10 @@ static void option_instat_callback(struct urb *urb); #define WETELECOM_PRODUCT_6802 0x6802 #define WETELECOM_PRODUCT_WMD300 0x6803 +/* OPPO products */ +#define OPPO_VENDOR_ID 0x22d9 +#define OPPO_PRODUCT_R11 0x276c + /* Device flags */ @@ -2155,6 +2159,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */ + { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 6415953963a9ca86113931da50af20b8a9df0cbd Mon Sep 17 00:00:00 2001 From: Yonglin Tan Date: Tue, 19 Jul 2022 19:28:00 +0800 Subject: [PATCH 073/228] USB: serial: option: add Quectel EM060K modem commit f766f3abe6dbc9bf8b56a5d53c87e5a17942c154 upstream. Add usb product id entry for the Quectel EM060K module. "MBIM mode": DIAG + NMEA + AT + MODEM + MBIM + QDSS T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 8 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2c7c ProdID=030b Rev= 5.04 S: Manufacturer=Quectel S: Product=EM060K-GL S: SerialNumber=89fb57db C:* #Ifs= 7 Cfg#= 1 Atr=a0 MxPwr=500mA A: FirstIf#= 8 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00 I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=40 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=ff Prot=40 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=ff Prot=40 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#= 8 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=88(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 9 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim I:* If#= 9 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0f(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#=12 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Yonglin Tan [ johan: mention QDSS port and sort entries ] Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index cf65cb84c3cae..bd6d624aa3753 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -253,6 +253,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_BG96 0x0296 #define QUECTEL_PRODUCT_EP06 0x0306 #define QUECTEL_PRODUCT_EM05G 0x030a +#define QUECTEL_PRODUCT_EM060K 0x030b #define QUECTEL_PRODUCT_EM12 0x0512 #define QUECTEL_PRODUCT_RM500Q 0x0800 #define QUECTEL_PRODUCT_EC200S_CN 0x6002 @@ -1142,6 +1143,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff), .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, From 577f84a6f1203a311914e7b8eadfe4a752f3fba1 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Wed, 10 Aug 2022 11:30:50 +0800 Subject: [PATCH 074/228] USB: serial: option: add support for Cinterion MV32-WA/WB RmNet mode commit 8ffe20d08f2c95d702c453020d03a4c568a988f0 upstream. We added PIDs for MV32-WA/WB MBIM mode before, now we need to add support for RmNet mode. Test evidence as below: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=03 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1e2d ProdID=00f3 Rev=05.04 S: Manufacturer=Cinterion S: Product=Cinterion PID 0x00F3 USB Mobile Broadband S: SerialNumber=d7b4be8d C: #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#=0x0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan I: If#=0x1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option I: If#=0x2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option I: If#=0x3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=03 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1e2d ProdID=00f4 Rev=05.04 S: Manufacturer=Cinterion S: Product=Cinterion PID 0x00F4 USB Mobile Broadband S: SerialNumber=d095087d C: #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#=0x0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan I: If#=0x1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option I: If#=0x2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option I: If#=0x3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option Signed-off-by: Slark Xiao [ johan: sort entries ] Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index bd6d624aa3753..a5e8374a8d710 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -439,6 +439,8 @@ static void option_instat_callback(struct urb *urb); #define CINTERION_PRODUCT_MV31_2_RMNET 0x00b9 #define CINTERION_PRODUCT_MV32_WA 0x00f1 #define CINTERION_PRODUCT_MV32_WB 0x00f2 +#define CINTERION_PRODUCT_MV32_WA_RMNET 0x00f3 +#define CINTERION_PRODUCT_MV32_WB_RMNET 0x00f4 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -2001,8 +2003,12 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(0)}, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA, 0xff), .driver_info = RSVD(3)}, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WA_RMNET, 0xff), + .driver_info = RSVD(0) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB, 0xff), .driver_info = RSVD(3)}, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_MV32_WB_RMNET, 0xff), + .driver_info = RSVD(0) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100), .driver_info = RSVD(4) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120), From b201f6203197f40a3d8acc9621f4b95841fa642a Mon Sep 17 00:00:00 2001 From: Pablo Sun Date: Thu, 4 Aug 2022 11:48:03 +0800 Subject: [PATCH 075/228] usb: typec: altmodes/displayport: correct pin assignment for UFP receptacles commit c1e5c2f0cb8a22ec2e14af92afc7006491bebabb upstream. Fix incorrect pin assignment values when connecting to a monitor with Type-C receptacle instead of a plug. According to specification, an UFP_D receptacle's pin assignment should came from the UFP_D pin assignments field (bit 23:16), while an UFP_D plug's assignments are described in the DFP_D pin assignments (bit 15:8) during Mode Discovery. For example the LG 27 UL850-W is a monitor with Type-C receptacle. The monitor responds to MODE DISCOVERY command with following DisplayPort Capability flag: dp->alt->vdo=0x140045 The existing logic only take cares of UPF_D plug case, and would take the bit 15:8 for this 0x140045 case. This results in an non-existing pin assignment 0x0 in dp_altmode_configure. To fix this problem a new set of macros are introduced to take plug/receptacle differences into consideration. Fixes: 0e3bb7d6894d ("usb: typec: Add driver for DisplayPort alternate mode") Cc: stable@vger.kernel.org Co-developed-by: Pablo Sun Co-developed-by: Macpaul Lin Reviewed-by: Guillaume Ranquet Reviewed-by: Heikki Krogerus Signed-off-by: Pablo Sun Signed-off-by: Macpaul Lin Link: https://lore.kernel.org/r/20220804034803.19486-1-macpaul.lin@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/displayport.c | 4 ++-- include/linux/usb/typec_dp.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index b7f094435b00a..998c1e3e318e1 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -88,8 +88,8 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con) case DP_STATUS_CON_UFP_D: case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */ conf |= DP_CONF_UFP_U_AS_UFP_D; - pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) & - DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo); + pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) & + DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo); break; default: break; diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index cfb916cccd316..8d09c2f0a9b80 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h @@ -73,6 +73,11 @@ enum { #define DP_CAP_USB BIT(7) #define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(15, 8)) >> 8) #define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(23, 16)) >> 16) +/* Get pin assignment taking plug & receptacle into consideration */ +#define DP_CAP_PIN_ASSIGN_UFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \ + DP_CAP_UFP_D_PIN_ASSIGN(_cap_) : DP_CAP_DFP_D_PIN_ASSIGN(_cap_)) +#define DP_CAP_PIN_ASSIGN_DFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \ + DP_CAP_DFP_D_PIN_ASSIGN(_cap_) : DP_CAP_UFP_D_PIN_ASSIGN(_cap_)) /* DisplayPort Status Update VDO bits */ #define DP_STATUS_CONNECTION(_status_) ((_status_) & 3) From 4be500c63911a94722abc5b7cb65cb103acbdb12 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel Date: Tue, 16 Aug 2022 13:16:24 +0300 Subject: [PATCH 076/228] usb: typec: intel_pmc_mux: Add new ACPI ID for Meteor Lake IOM device commit 1b1b672cc1d4fb3065dac79efb8901bd6244ef69 upstream. This adds the necessary ACPI ID for Intel Meteor Lake IOM devices. The callback function is_memory() is modified so that it also checks if the resource descriptor passed to it is a memory type "Address Space Resource Descriptor". On Intel Meteor Lake the ACPI memory resource is not described using the "32-bit Memory Range Descriptor" because the memory is outside of the 32-bit address space. The memory resource is described using the "Address Space Resource Descriptor" instead. Intel Meteor Lake is the first platform to describe the memory resource for this device with Address Space Resource Descriptor, but it most likely will not be the last. Therefore the change to the is_memory() callback function is made generic. Signed-off-by: Utkarsh Patel Cc: stable@vger.kernel.org [ heikki: Rewrote the commit message. ] Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220816101629.69054-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/intel_pmc_mux.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 2cdd22130834e..5daec9d79e94f 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -554,9 +554,11 @@ static int pmc_usb_register_port(struct pmc_usb *pmc, int index, static int is_memory(struct acpi_resource *res, void *data) { - struct resource r; + struct resource_win win = {}; + struct resource *r = &win.res; - return !acpi_dev_resource_memory(res, &r); + return !(acpi_dev_resource_memory(res, r) || + acpi_dev_resource_address_space(res, &win)); } /* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */ @@ -566,6 +568,9 @@ static const struct acpi_device_id iom_acpi_ids[] = { /* AlderLake */ { "INTC1079", 0x160, }, + + /* Meteor Lake */ + { "INTC107A", 0x160, }, {} }; From ea72b22a05ea546ded582edfdbb2aa29993b1e72 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 17 Aug 2022 14:54:10 -0700 Subject: [PATCH 077/228] usb: typec: tcpm: Return ENOTSUPP for power supply prop writes commit f2d38edc5e3375e56b4a30d5b66cefd385a2b38c upstream. When the port does not support USB PD, prevent transition to PD only states when power supply property is written. In this case, TCPM transitions to SNK_NEGOTIATE_CAPABILITIES which should not be the case given that the port is not pd_capable. [ 84.308251] state change SNK_READY -> SNK_NEGOTIATE_CAPABILITIES [rev3 NONE_AMS] [ 84.308335] Setting usb_comm capable false [ 84.323367] set_auto_vbus_discharge_threshold mode:3 pps_active:n vbus:5000 ret:0 [ 84.323376] state change SNK_NEGOTIATE_CAPABILITIES -> SNK_WAIT_CAPABILITIES [rev3 NONE_AMS] Fixes: e9e6e164ed8f6 ("usb: typec: tcpm: Support non-PD mode") Cc: stable@vger.kernel.org Reviewed-by: Heikki Krogerus Signed-off-by: Badhri Jagan Sridharan Link: https://lore.kernel.org/r/20220817215410.1807477-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 5fce795b69c7f..33aadc0a29ea8 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -6213,6 +6213,13 @@ static int tcpm_psy_set_prop(struct power_supply *psy, struct tcpm_port *port = power_supply_get_drvdata(psy); int ret; + /* + * All the properties below are related to USB PD. The check needs to be + * property specific when a non-pd related property is added. + */ + if (!port->pd_supported) + return -EOPNOTSUPP; + switch (psp) { case POWER_SUPPLY_PROP_ONLINE: ret = tcpm_psy_set_online(port, val); From 48917032c702fc4889f7c67f4f0969636ee51127 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 23 Aug 2022 19:58:42 +0200 Subject: [PATCH 078/228] usb: dwc2: fix wrong order of phy_power_on and phy_init commit f9b995b49a07bd0d43b0e490f59be84415c745ae upstream. Since 1599069a62c6 ("phy: core: Warn when phy_power_on is called before phy_init") the driver complains. In my case (Amlogic SoC) the warning is: phy phy-fe03e000.phy.2: phy_power_on was called before phy_init So change the order of the two calls. The same change has to be done to the order of phy_exit() and phy_power_off(). Fixes: 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") Cc: stable@vger.kernel.org Acked-by: Minas Harutyunyan Acked-by: Marek Szyprowski Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/dfcc6b40-2274-4e86-e73c-5c5e6aa3e046@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c331a5128c2c0..265d437ca0f11 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -154,9 +154,9 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) } else if (hsotg->plat && hsotg->plat->phy_init) { ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } else { - ret = phy_power_on(hsotg->phy); + ret = phy_init(hsotg->phy); if (ret == 0) - ret = phy_init(hsotg->phy); + ret = phy_power_on(hsotg->phy); } return ret; @@ -188,9 +188,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) } else if (hsotg->plat && hsotg->plat->phy_exit) { ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); } else { - ret = phy_exit(hsotg->phy); + ret = phy_power_off(hsotg->phy); if (ret == 0) - ret = phy_power_off(hsotg->phy); + ret = phy_exit(hsotg->phy); } if (ret) return ret; From f1eb9e5d2f6e02f35cc98f2bcae5427d79db6aa1 Mon Sep 17 00:00:00 2001 From: Pawel Laszczak Date: Thu, 25 Aug 2022 08:21:37 +0200 Subject: [PATCH 079/228] usb: cdns3: fix issue with rearming ISO OUT endpoint commit b46a6b09fa056042a302b181a1941f0056944603 upstream. ISO OUT endpoint is enabled during queuing first usb request in transfer ring and disabled when TRBERR is reported by controller. After TRBERR and before next transfer added to TR driver must again reenable endpoint but does not. To solve this issue during processing TRBERR event driver must set the flag EP_UPDATE_EP_TRBADDR in priv_ep->flags field. Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") cc: Acked-by: Peter Chen Signed-off-by: Pawel Laszczak Link: https://lore.kernel.org/r/20220825062137.5766-1-pawell@cadence.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 3f1ce89110776..621e6965d4ae6 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -1690,6 +1690,7 @@ static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep) ep_cfg &= ~EP_CFG_ENABLE; writel(ep_cfg, &priv_dev->regs->ep_cfg); priv_ep->flags &= ~EP_QUIRK_ISO_OUT_EN; + priv_ep->flags |= EP_UPDATE_EP_TRBADDR; } cdns3_transfer_completed(priv_dev, priv_ep); } else if (!(priv_ep->flags & EP_STALLED) && From bf6e4243f80bb64565d26f997afaf5d08da32c11 Mon Sep 17 00:00:00 2001 From: Pawel Laszczak Date: Thu, 25 Aug 2022 08:22:07 +0200 Subject: [PATCH 080/228] usb: cdns3: fix incorrect handling TRB_SMM flag for ISOC transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d5dcc33677d7415c5f23b3c052f9e80cbab9ea4e upstream. The TRB_SMM flag indicates that DMA has completed the TD service with this TRB. Usually it’s a last TRB in TD. In case of ISOC transfer for bInterval > 1 each ISOC transfer contains more than one TD associated with usb request (one TD per ITP). In such case the TRB_SMM flag will be set in every TD and driver will recognize the end of transfer after processing the first TD with TRB_SMM. In result driver stops updating request->actual and returns incorrect actual length. To fix this issue driver additionally must check TRB_CHAIN which is not used for isochronous transfers. Fixes: 249f0a25e8be ("usb: cdns3: gadget: handle sg list use case at completion correctly") cc: Acked-by: Peter Chen Signed-off-by: Pawel Laszczak Link: https://lore.kernel.org/r/20220825062207.5824-1-pawell@cadence.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 621e6965d4ae6..1802f6818e632 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -1530,7 +1530,8 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, TRB_LEN(le32_to_cpu(trb->length)); if (priv_req->num_of_trb > 1 && - le32_to_cpu(trb->control) & TRB_SMM) + le32_to_cpu(trb->control) & TRB_SMM && + le32_to_cpu(trb->control) & TRB_CHAIN) transfer_end = true; cdns3_ep_inc_deq(priv_ep); From 0f8b5d706dcd96f6c204c23d0c0328e912620dc7 Mon Sep 17 00:00:00 2001 From: Thierry GUIBERT Date: Fri, 19 Aug 2022 10:17:02 +0200 Subject: [PATCH 081/228] USB: cdc-acm: Add Icom PMR F3400 support (0c26:0020) commit a10bc71729b236fe36de0d8e4d35c959fd8dec3a upstream. Supports for ICOM F3400 and ICOM F4400 PMR radios in CDC-ACM driver enabling the AT serial port. The Vendor Id is 0x0C26 The Product ID is 0x0020 Output of lsusb : Bus 001 Device 009: ID 0c26:0020 Prolific Technology Inc. ICOM Radio Couldn't open device, some information will be missing Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 2 Communications bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0c26 Prolific Technology Inc. idProduct 0x0020 bcdDevice 0.00 iManufacturer 1 ICOM Inc. iProduct 2 ICOM Radio iSerial 3 *obfuscated* bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0030 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xc0 Self Powered MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 12 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Signed-off-by: Thierry GUIBERT Cc: stable Link: https://lore.kernel.org/r/20220819081702.84118-1-thierry.guibert@croix-rouge.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7b2e2420ecaea..adc154b691d05 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1814,6 +1814,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ }, + { USB_DEVICE(0x0c26, 0x0020), /* Icom ICF3400 Serie */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, From efdfa236a085ba2b597c4ff8f1e61a3d6488f1c8 Mon Sep 17 00:00:00 2001 From: Witold Lipieta Date: Tue, 9 Aug 2022 13:29:11 +0200 Subject: [PATCH 082/228] usb-storage: Add ignore-residue quirk for NXP PN7462AU commit 2aa48857ad52236a9564c71183d6cc8893becd41 upstream. This is USB mass storage primary boot loader for code download on NXP PN7462AU. Without the quirk it is impossible to write whole memory at once as device restarts during the write due to bogus residue values reported. Acked-by: Alan Stern Cc: stable Signed-off-by: Witold Lipieta Link: https://lore.kernel.org/r/20220809112911.462776-1-witold.lipieta@thaumatec.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1a05e3dcfec8a..4993227ab2930 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2294,6 +2294,13 @@ UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), +/* Reported by Witold Lipieta */ +UNUSUAL_DEV( 0x1fc9, 0x0117, 0x0100, 0x0100, + "NXP Semiconductors", + "PN7462AU", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Supplied with some Castlewood ORB removable drives */ UNUSUAL_DEV( 0x2027, 0xa001, 0x0000, 0x9999, "Double-H Technology", From 047a4d0f7924e47558ea94e92f89ba079df3b784 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Fri, 19 Aug 2022 18:53:43 +0200 Subject: [PATCH 083/228] s390/hugetlb: fix prepare_hugepage_range() check for 2 GB hugepages commit 7c8d42fdf1a84b1a0dd60d6528309c8ec127e87c upstream. The alignment check in prepare_hugepage_range() is wrong for 2 GB hugepages, it only checks for 1 MB hugepage alignment. This can result in kernel crash in __unmap_hugepage_range() at the BUG_ON(start & ~huge_page_mask(h)) alignment check, for mappings created with MAP_FIXED at unaligned address. Fix this by correctly handling multiple hugepage sizes, similar to the generic version of prepare_hugepage_range(). Fixes: d08de8e2d867 ("s390/mm: add support for 2GB hugepages") Cc: # 4.8+ Acked-by: Alexander Gordeev Signed-off-by: Gerald Schaefer Signed-off-by: Vasily Gorbik Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/hugetlb.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index 60f9241e5e4a6..d3642fb634bd9 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h @@ -28,9 +28,11 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, static inline int prepare_hugepage_range(struct file *file, unsigned long addr, unsigned long len) { - if (len & ~HPAGE_MASK) + struct hstate *h = hstate_file(file); + + if (len & ~huge_page_mask(h)) return -EINVAL; - if (addr & ~HPAGE_MASK) + if (addr & ~huge_page_mask(h)) return -EINVAL; return 0; } From 4e22a43ec71714859cc68f4384ccec8a88ff6e96 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 26 Aug 2022 16:55:44 -0700 Subject: [PATCH 084/228] s390: fix nospec table alignments commit c9305b6c1f52060377c72aebe3a701389e9f3172 upstream. Add proper alignment for .nospec_call_table and .nospec_return_table in vmlinux. [hca@linux.ibm.com]: The problem with the missing alignment of the nospec tables exist since a long time, however only since commit e6ed91fd0768 ("s390/alternatives: remove padding generation code") and with CONFIG_RELOCATABLE=n the kernel may also crash at boot time. The above named commit reduced the size of struct alt_instr by one byte, so its new size is 11 bytes. Therefore depending on the number of cpu alternatives the size of the __alt_instructions array maybe odd, which again also causes that the addresses of the nospec tables will be odd. If the address of __nospec_call_start is odd and the kernel is compiled With CONFIG_RELOCATABLE=n the compiler may generate code that loads the address of __nospec_call_start with a 'larl' instruction. This will generate incorrect code since the 'larl' instruction only works with even addresses. In result the members of the nospec tables will be accessed with an off-by-one offset, which subsequently may lead to addressing exceptions within __nospec_revert(). Fixes: f19fbd5ed642 ("s390: introduce execute-trampolines for branches") Signed-off-by: Josh Poimboeuf Link: https://lore.kernel.org/r/8719bf1ce4a72ebdeb575200290094e9ce047bcc.1661557333.git.jpoimboe@kernel.org Cc: # 4.16 Reviewed-by: Heiko Carstens Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 42c43521878ff..b508ccad4856d 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -132,6 +132,7 @@ SECTIONS /* * Table with the patch locations to undo expolines */ + . = ALIGN(4); .nospec_call_table : { __nospec_call_start = . ; *(.s390_indirect*) From c548b99e1c37db6f7df86ecfe9a1f895d6c5966e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 26 Aug 2022 15:31:32 -0400 Subject: [PATCH 085/228] USB: core: Prevent nested device-reset calls commit 9c6d778800b921bde3bff3cff5003d1650f942d1 upstream. Automatic kernel fuzzing revealed a recursive locking violation in usb-storage: ============================================ WARNING: possible recursive locking detected 5.18.0 #3 Not tainted -------------------------------------------- kworker/1:3/1205 is trying to acquire lock: ffff888018638db8 (&us_interface_key[i]){+.+.}-{3:3}, at: usb_stor_pre_reset+0x35/0x40 drivers/usb/storage/usb.c:230 but task is already holding lock: ffff888018638db8 (&us_interface_key[i]){+.+.}-{3:3}, at: usb_stor_pre_reset+0x35/0x40 drivers/usb/storage/usb.c:230 ... stack backtrace: CPU: 1 PID: 1205 Comm: kworker/1:3 Not tainted 5.18.0 #3 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Workqueue: usb_hub_wq hub_event Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 print_deadlock_bug kernel/locking/lockdep.c:2988 [inline] check_deadlock kernel/locking/lockdep.c:3031 [inline] validate_chain kernel/locking/lockdep.c:3816 [inline] __lock_acquire.cold+0x152/0x3ca kernel/locking/lockdep.c:5053 lock_acquire kernel/locking/lockdep.c:5665 [inline] lock_acquire+0x1ab/0x520 kernel/locking/lockdep.c:5630 __mutex_lock_common kernel/locking/mutex.c:603 [inline] __mutex_lock+0x14f/0x1610 kernel/locking/mutex.c:747 usb_stor_pre_reset+0x35/0x40 drivers/usb/storage/usb.c:230 usb_reset_device+0x37d/0x9a0 drivers/usb/core/hub.c:6109 r871xu_dev_remove+0x21a/0x270 drivers/staging/rtl8712/usb_intf.c:622 usb_unbind_interface+0x1bd/0x890 drivers/usb/core/driver.c:458 device_remove drivers/base/dd.c:545 [inline] device_remove+0x11f/0x170 drivers/base/dd.c:537 __device_release_driver drivers/base/dd.c:1222 [inline] device_release_driver_internal+0x1a7/0x2f0 drivers/base/dd.c:1248 usb_driver_release_interface+0x102/0x180 drivers/usb/core/driver.c:627 usb_forced_unbind_intf+0x4d/0xa0 drivers/usb/core/driver.c:1118 usb_reset_device+0x39b/0x9a0 drivers/usb/core/hub.c:6114 This turned out not to be an error in usb-storage but rather a nested device reset attempt. That is, as the rtl8712 driver was being unbound from a composite device in preparation for an unrelated USB reset (that driver does not have pre_reset or post_reset callbacks), its ->remove routine called usb_reset_device() -- thus nesting one reset call within another. Performing a reset as part of disconnect processing is a questionable practice at best. However, the bug report points out that the USB core does not have any protection against nested resets. Adding a reset_in_progress flag and testing it will prevent such errors in the future. Link: https://lore.kernel.org/all/CAB7eexKUpvX-JNiLzhXBDWgfg2T9e9_0Tw4HQ6keN==voRbP0g@mail.gmail.com/ Cc: stable@vger.kernel.org Reported-and-tested-by: Rondreis Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/YwkflDxvg0KWqyZK@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 10 ++++++++++ include/linux/usb.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ac6c5ccfe1cb7..23896c8e018a3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -6043,6 +6043,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev) * the reset is over (using their post_reset method). * * Return: The same as for usb_reset_and_verify_device(). + * However, if a reset is already in progress (for instance, if a + * driver doesn't have pre_ or post_reset() callbacks, and while + * being unbound or re-bound during the ongoing reset its disconnect() + * or probe() routine tries to perform a second, nested reset), the + * routine returns -EINPROGRESS. * * Note: * The caller must own the device lock. For example, it's safe to use @@ -6076,6 +6081,10 @@ int usb_reset_device(struct usb_device *udev) return -EISDIR; } + if (udev->reset_in_progress) + return -EINPROGRESS; + udev->reset_in_progress = 1; + port_dev = hub->ports[udev->portnum - 1]; /* @@ -6140,6 +6149,7 @@ int usb_reset_device(struct usb_device *udev) usb_autosuspend_device(udev); memalloc_noio_restore(noio_flag); + udev->reset_in_progress = 0; return ret; } EXPORT_SYMBOL_GPL(usb_reset_device); diff --git a/include/linux/usb.h b/include/linux/usb.h index 7ccaa76a9a968..da1329b85329b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -575,6 +575,7 @@ struct usb3_lpm_parameters { * @devaddr: device address, XHCI: assigned by HW, others: same as devnum * @can_submit: URBs may be submitted * @persist_enabled: USB_PERSIST enabled for this device + * @reset_in_progress: the device is being reset * @have_langid: whether string_langid is valid * @authorized: policy has said we can use it; * (user space) policy determines if we authorize this device to be @@ -661,6 +662,7 @@ struct usb_device { unsigned can_submit:1; unsigned persist_enabled:1; + unsigned reset_in_progress:1; unsigned have_langid:1; unsigned authorized:1; unsigned authenticated:1; From 27102b39b6d09a0afb37194107c03331b7634a81 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 19 Aug 2022 16:05:55 +0800 Subject: [PATCH 086/228] usb: xhci-mtk: relax TT periodic bandwidth allocation commit 8b13ea05117ffad4727b0971ed09122d5c91c4dc upstream. Currently uses the worst case byte budgets on FS/LS bus bandwidth, for example, for an isochronos IN endpoint with 192 bytes budget, it will consume the whole 5 uframes(188 * 5) while the actual FS bus budget should be just 192 bytes. It cause that many usb audio headsets with 3 interfaces (audio input, audio output, and HID) cannot be configured. To improve it, changes to use "approximate" best case budget for FS/LS bandwidth management. For the same endpoint from the above example, the approximate best case budget is now reduced to (188 * 2) bytes. Signed-off-by: Chunfeng Yun Cc: stable Link: https://lore.kernel.org/r/20220819080556.32215-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index f91a304320563..d9e25fea1660e 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -476,7 +476,6 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) { - u32 extra_cs_count; u32 start_ss, last_ss; u32 start_cs, last_cs; @@ -512,18 +511,12 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) if (last_cs > 7) return -ESCH_CS_OVERFLOW; - if (sch_ep->ep_type == ISOC_IN_EP) - extra_cs_count = (last_cs == 7) ? 1 : 2; - else /* ep_type : INTR IN / INTR OUT */ - extra_cs_count = 1; - - cs_count += extra_cs_count; if (cs_count > 7) cs_count = 7; /* HW limit */ sch_ep->cs_count = cs_count; - /* one for ss, the other for idle */ - sch_ep->num_budget_microframes = cs_count + 2; + /* ss, idle are ignored */ + sch_ep->num_budget_microframes = cs_count; /* * if interval=1, maxp >752, num_budge_micoframe is larger From 299f4f420f23c94da9b6cbed0812045578007d4e Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 19 Aug 2022 16:05:56 +0800 Subject: [PATCH 087/228] usb: xhci-mtk: fix bandwidth release issue commit 6020f480004a80cdad4ae5ee180a231c4f65595b upstream. This happens when @udev->reset_resume is set to true, when usb resume, the flow as below: - hub_resume - usb_disable_interface - usb_disable_endpoint - usb_hcd_disable_endpoint - xhci_endpoint_disable // it set @ep->hcpriv to NULL Then when reset usb device, it will drop allocated endpoints, the flow as below: - usb_reset_and_verify_device - usb_hcd_alloc_bandwidth - xhci_mtk_drop_ep but @ep->hcpriv is already set to NULL, the bandwidth will be not released anymore. Due to the added endponts are stored in hash table, we can drop the check of @ep->hcpriv. Fixes: 4ce186665e7c ("usb: xhci-mtk: Do not use xhci's virt_dev in drop_endpoint") Cc: stable Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220819080556.32215-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index d9e25fea1660e..9d8094afcc8bc 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -815,8 +815,8 @@ int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, if (ret) return ret; - if (ep->hcpriv) - drop_ep_quirk(hcd, udev, ep); + /* needn't check @ep->hcpriv, xhci_endpoint_disable set it NULL */ + drop_ep_quirk(hcd, udev, ep); return 0; } From 7da29a2cc5147b1584113280deb527e3ee2001f4 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 27 Aug 2022 08:45:10 +0530 Subject: [PATCH 088/228] usb: gadget: mass_storage: Fix cdrom data transfers on MAC-OS commit 9d4dc16ec71bd6368548e9743223e449b4377fc7 upstream. During cdrom emulation, the response to read_toc command must contain the cdrom address as the number of sectors (2048 byte sized blocks) represented either as an absolute value (when MSF bit is '0') or in terms of PMin/PSec/PFrame (when MSF bit is set to '1'). Incase of cdrom, the fsg_lun_open call sets the sector size to 2048 bytes. When MAC OS sends a read_toc request with MSF set to '1', the store_cdrom_address assumes that the address being provided is the LUN size represented in 512 byte sized blocks instead of 2048. It tries to modify the address further to convert it to 2048 byte sized blocks and store it in MSF format. This results in data transfer failures as the cdrom address being provided in the read_toc response is incorrect. Fixes: 3f565a363cee ("usb: gadget: storage: adapt logic block size to bound block devices") Cc: stable@vger.kernel.org Acked-by: Alan Stern Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1661570110-19127-1-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/storage_common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index b859a158a4140..e122050eebaf1 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -294,8 +294,10 @@ EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); void store_cdrom_address(u8 *dest, int msf, u32 addr) { if (msf) { - /* Convert to Minutes-Seconds-Frames */ - addr >>= 2; /* Convert to 2048-byte frames */ + /* + * Convert to Minutes-Seconds-Frames. + * Sector size is already set to 2048 bytes. + */ addr += 2*75; /* Lead-in occupies 2 seconds */ dest[3] = addr % 75; /* Frames */ addr /= 75; From 253ec5fb84057c681a30d20314b8662fe424e3df Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 17 Aug 2022 11:40:26 -0700 Subject: [PATCH 089/228] driver core: Don't probe devices after bus_type.match() probe deferral commit 25e9fbf0fd38868a429feabc38abebfc6dbf6542 upstream. Both __device_attach_driver() and __driver_attach() check the return code of the bus_type.match() function to see if the device needs to be added to the deferred probe list. After adding the device to the list, the logic attempts to bind the device to the driver anyway, as if the device had matched with the driver, which is not correct. If __device_attach_driver() detects that the device in question is not ready to match with a driver on the bus, then it doesn't make sense for the device to attempt to bind with the current driver or continue attempting to match with any of the other drivers on the bus. So, update the logic in __device_attach_driver() to reflect this. If __driver_attach() detects that a driver tried to match with a device that is not ready to match yet, then the driver should not attempt to bind with the device. However, the driver can still attempt to match and bind with other devices on the bus, as drivers can be bound to multiple devices. So, update the logic in __driver_attach() to reflect this. Fixes: 656b8035b0ee ("ARM: 8524/1: driver cohandle -EPROBE_DEFER from bus_type.match()") Cc: stable@vger.kernel.org Cc: Saravana Kannan Reported-by: Guenter Roeck Tested-by: Guenter Roeck Tested-by: Linus Walleij Reviewed-by: Saravana Kannan Signed-off-by: Isaac J. Manjarres Link: https://lore.kernel.org/r/20220817184026.3468620-1-isaacmanjarres@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 70e9ee8a10f79..63cc011188109 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -877,6 +877,11 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) dev_dbg(dev, "Device match requests probe deferral\n"); dev->can_match = true; driver_deferred_probe_add(dev); + /* + * Device can't match with a driver right now, so don't attempt + * to match or bind with other drivers on the bus. + */ + return ret; } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d\n", ret); return ret; @@ -1115,6 +1120,11 @@ static int __driver_attach(struct device *dev, void *data) dev_dbg(dev, "Device match requests probe deferral\n"); dev->can_match = true; driver_deferred_probe_add(dev); + /* + * Driver could not match with device, but may match with + * another device on the bus. + */ + return 0; } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d\n", ret); return ret; From 552ba102a6898630a7d16887f29e606d6fabe508 Mon Sep 17 00:00:00 2001 From: Siddh Raman Pant Date: Sun, 14 Aug 2022 20:45:12 +0530 Subject: [PATCH 090/228] wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected commit 15bc8966b6d3a5b9bfe4c9facfa02f2b69b1e5f0 upstream. When we are not connected to a channel, sending channel "switch" announcement doesn't make any sense. The BSS list is empty in that case. This causes the for loop in cfg80211_get_bss() to be bypassed, so the function returns NULL (check line 1424 of net/wireless/scan.c), causing the WARN_ON() in ieee80211_ibss_csa_beacon() to get triggered (check line 500 of net/mac80211/ibss.c), which was consequently reported on the syzkaller dashboard. Thus, check if we have an existing connection before generating the CSA beacon in ieee80211_ibss_finish_csa(). Cc: stable@vger.kernel.org Fixes: cd7760e62c2a ("mac80211: add support for CSA in IBSS mode") Link: https://syzkaller.appspot.com/bug?id=05603ef4ae8926761b678d2939a3b2ad28ab9ca6 Reported-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com Signed-off-by: Siddh Raman Pant Tested-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20220814151512.9985-1-code@siddh.me Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5d6ca4c3e6981..1e133ca58e789 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -534,6 +534,10 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); + /* When not connected/joined, sending CSA doesn't make sense. */ + if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) + return -ENOLINK; + /* update cfg80211 bss information with the new channel */ if (!is_zero_ether_addr(ifibss->bssid)) { cbss = cfg80211_get_bss(sdata->local->hw.wiphy, From 5d20c6f932f2758078d0454729129c894fe353e7 Mon Sep 17 00:00:00 2001 From: Siddh Raman Pant Date: Sat, 20 Aug 2022 01:33:40 +0530 Subject: [PATCH 091/228] wifi: mac80211: Fix UAF in ieee80211_scan_rx() commit 60deb9f10eec5c6a20252ed36238b55d8b614a2c upstream. ieee80211_scan_rx() tries to access scan_req->flags after a null check, but a UAF is observed when the scan is completed and __ieee80211_scan_completed() executes, which then calls cfg80211_scan_done() leading to the freeing of scan_req. Since scan_req is rcu_dereference()'d, prevent the racing in __ieee80211_scan_completed() by ensuring that from mac80211's POV it is no longer accessed from an RCU read critical section before we call cfg80211_scan_done(). Cc: stable@vger.kernel.org Link: https://syzkaller.appspot.com/bug?extid=f9acff9bf08a845f225d Reported-by: syzbot+f9acff9bf08a845f225d@syzkaller.appspotmail.com Suggested-by: Johannes Berg Signed-off-by: Siddh Raman Pant Link: https://lore.kernel.org/r/20220819200340.34826-1-code@siddh.me Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/scan.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 887f945bb12d4..d6afaacaf7ef8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) scan_req = rcu_dereference_protected(local->scan_req, lockdep_is_held(&local->mtx)); - if (scan_req != local->int_scan_req) { - local->scan_info.aborted = aborted; - cfg80211_scan_done(scan_req, &local->scan_info); - } RCU_INIT_POINTER(local->scan_req, NULL); RCU_INIT_POINTER(local->scan_sdata, NULL); local->scanning = 0; local->scan_chandef.chan = NULL; + synchronize_rcu(); + + if (scan_req != local->int_scan_req) { + local->scan_info.aborted = aborted; + cfg80211_scan_done(scan_req, &local->scan_info); + } + /* Set power back to normal operating levels. */ ieee80211_hw_config(local, 0); From 57f1407ca1662288d41c509103f2a1462d1c4dd4 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 29 Aug 2022 12:01:21 +0200 Subject: [PATCH 092/228] ip: fix triggering of 'icmp redirect' commit eb55dc09b5dd040232d5de32812cc83001a23da6 upstream. __mkroute_input() uses fib_validate_source() to trigger an icmp redirect. My understanding is that fib_validate_source() is used to know if the src address and the gateway address are on the same link. For that, fib_validate_source() returns 1 (same link) or 0 (not the same network). __mkroute_input() is the only user of these positive values, all other callers only look if the returned value is negative. Since the below patch, fib_validate_source() didn't return anymore 1 when both addresses are on the same network, because the route lookup returns RT_SCOPE_LINK instead of RT_SCOPE_HOST. But this is, in fact, right. Let's adapat the test to return 1 again when both addresses are on the same link. CC: stable@vger.kernel.org Fixes: 747c14307214 ("ip: fix dflt addr selection for connected nexthop") Reported-by: kernel test robot Reported-by: Heng Qi Signed-off-by: Nicolas Dichtel Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20220829100121.3821-1-nicolas.dichtel@6wind.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 1eb7795edb9dc..1452bb72b7d9c 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -389,7 +389,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, dev_match = dev_match || (res.type == RTN_LOCAL && dev == net->loopback_dev); if (dev_match) { - ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST; + ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK; return ret; } if (no_addr) @@ -401,7 +401,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, ret = 0; if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) { if (res.type == RTN_UNICAST) - ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST; + ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_LINK; } return ret; From 4b9f3743a8220989f8289138f7414bc56fb5e425 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 25 Aug 2022 13:36:45 +0200 Subject: [PATCH 093/228] net: Use u64_stats_fetch_begin_irq() for stats fetch. commit 278d3ba61563ceed3cb248383ced19e14ec7bc1f upstream. On 32bit-UP u64_stats_fetch_begin() disables only preemption. If the reader is in preemptible context and the writer side (u64_stats_update_begin*()) runs in an interrupt context (IRQ or softirq) then the writer can update the stats during the read operation. This update remains undetected. Use u64_stats_fetch_begin_irq() to ensure the stats fetch on 32bit-UP are not interrupted by a writer. 32bit-SMP remains unaffected by this change. Cc: "David S. Miller" Cc: Catherine Sullivan Cc: David Awogbemila Cc: Dimitris Michailidis Cc: Eric Dumazet Cc: Hans Ulli Kroll Cc: Jakub Kicinski Cc: Jeroen de Borst Cc: Johannes Berg Cc: Linus Walleij Cc: Paolo Abeni Cc: Simon Horman Cc: linux-arm-kernel@lists.infradead.org Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Cc: oss-drivers@corigine.com Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cortina/gemini.c | 24 +++++++++---------- drivers/net/ethernet/google/gve/gve_ethtool.c | 16 ++++++------- drivers/net/ethernet/google/gve/gve_main.c | 12 +++++----- drivers/net/ethernet/huawei/hinic/hinic_rx.c | 4 ++-- drivers/net/ethernet/huawei/hinic/hinic_tx.c | 4 ++-- .../ethernet/netronome/nfp/nfp_net_common.c | 8 +++---- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 8 +++---- drivers/net/netdevsim/netdev.c | 4 ++-- net/mac80211/sta_info.c | 8 +++---- net/mpls/af_mpls.c | 4 ++-- 10 files changed, 46 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 012ca11a38cc1..8361faf03e429 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -1920,7 +1920,7 @@ static void gmac_get_stats64(struct net_device *netdev, /* Racing with RX NAPI */ do { - start = u64_stats_fetch_begin(&port->rx_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); stats->rx_packets = port->stats.rx_packets; stats->rx_bytes = port->stats.rx_bytes; @@ -1932,11 +1932,11 @@ static void gmac_get_stats64(struct net_device *netdev, stats->rx_crc_errors = port->stats.rx_crc_errors; stats->rx_frame_errors = port->stats.rx_frame_errors; - } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); /* Racing with MIB and TX completion interrupts */ do { - start = u64_stats_fetch_begin(&port->ir_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); stats->tx_errors = port->stats.tx_errors; stats->tx_packets = port->stats.tx_packets; @@ -1946,15 +1946,15 @@ static void gmac_get_stats64(struct net_device *netdev, stats->rx_missed_errors = port->stats.rx_missed_errors; stats->rx_fifo_errors = port->stats.rx_fifo_errors; - } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); /* Racing with hard_start_xmit */ do { - start = u64_stats_fetch_begin(&port->tx_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); stats->tx_dropped = port->stats.tx_dropped; - } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); stats->rx_dropped += stats->rx_missed_errors; } @@ -2032,18 +2032,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, /* Racing with MIB interrupt */ do { p = values; - start = u64_stats_fetch_begin(&port->ir_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); for (i = 0; i < RX_STATS_NUM; i++) *p++ = port->hw_stats[i]; - } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); values = p; /* Racing with RX NAPI */ do { p = values; - start = u64_stats_fetch_begin(&port->rx_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); for (i = 0; i < RX_STATUS_NUM; i++) *p++ = port->rx_stats[i]; @@ -2051,13 +2051,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, *p++ = port->rx_csum_stats[i]; *p++ = port->rx_napi_exits; - } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); values = p; /* Racing with TX start_xmit */ do { p = values; - start = u64_stats_fetch_begin(&port->tx_stats_syncp); + start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); for (i = 0; i < TX_MAX_FRAGS; i++) { *values++ = port->tx_frag_stats[i]; @@ -2066,7 +2066,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, *values++ = port->tx_frags_linearized; *values++ = port->tx_hw_csummed; - } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); + } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); } static int gmac_get_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index 716e6240305d9..878329ddcf8df 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -174,14 +174,14 @@ gve_get_ethtool_stats(struct net_device *netdev, struct gve_rx_ring *rx = &priv->rx[ring]; start = - u64_stats_fetch_begin(&priv->rx[ring].statss); + u64_stats_fetch_begin_irq(&priv->rx[ring].statss); tmp_rx_pkts = rx->rpackets; tmp_rx_bytes = rx->rbytes; tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; tmp_rx_desc_err_dropped_pkt = rx->rx_desc_err_dropped_pkt; - } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, start)); rx_pkts += tmp_rx_pkts; rx_bytes += tmp_rx_bytes; @@ -195,10 +195,10 @@ gve_get_ethtool_stats(struct net_device *netdev, if (priv->tx) { do { start = - u64_stats_fetch_begin(&priv->tx[ring].statss); + u64_stats_fetch_begin_irq(&priv->tx[ring].statss); tmp_tx_pkts = priv->tx[ring].pkt_done; tmp_tx_bytes = priv->tx[ring].bytes_done; - } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, start)); tx_pkts += tmp_tx_pkts; tx_bytes += tmp_tx_bytes; @@ -256,13 +256,13 @@ gve_get_ethtool_stats(struct net_device *netdev, data[i++] = rx->cnt; do { start = - u64_stats_fetch_begin(&priv->rx[ring].statss); + u64_stats_fetch_begin_irq(&priv->rx[ring].statss); tmp_rx_bytes = rx->rbytes; tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; tmp_rx_desc_err_dropped_pkt = rx->rx_desc_err_dropped_pkt; - } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, start)); data[i++] = tmp_rx_bytes; /* rx dropped packets */ @@ -323,9 +323,9 @@ gve_get_ethtool_stats(struct net_device *netdev, } do { start = - u64_stats_fetch_begin(&priv->tx[ring].statss); + u64_stats_fetch_begin_irq(&priv->tx[ring].statss); tmp_tx_bytes = tx->bytes_done; - } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, start)); data[i++] = tmp_tx_bytes; data[i++] = tx->wake_queue; diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 68552848d3888..49850cf7cfafd 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -51,10 +51,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { do { start = - u64_stats_fetch_begin(&priv->rx[ring].statss); + u64_stats_fetch_begin_irq(&priv->rx[ring].statss); packets = priv->rx[ring].rpackets; bytes = priv->rx[ring].rbytes; - } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, start)); s->rx_packets += packets; s->rx_bytes += bytes; @@ -64,10 +64,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { do { start = - u64_stats_fetch_begin(&priv->tx[ring].statss); + u64_stats_fetch_begin_irq(&priv->tx[ring].statss); packets = priv->tx[ring].pkt_done; bytes = priv->tx[ring].bytes_done; - } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, start)); s->tx_packets += packets; s->tx_bytes += bytes; @@ -1260,9 +1260,9 @@ void gve_handle_report_stats(struct gve_priv *priv) } do { - start = u64_stats_fetch_begin(&priv->tx[idx].statss); + start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss); tx_bytes = priv->tx[idx].bytes_done; - } while (u64_stats_fetch_retry(&priv->tx[idx].statss, start)); + } while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start)); stats[stats_idx++] = (struct stats) { .stat_name = cpu_to_be32(TX_WAKE_CNT), .value = cpu_to_be64(priv->tx[idx].wake_queue), diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c index a102d486c4350..d11ec69a2e17d 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c @@ -74,14 +74,14 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats) unsigned int start; do { - start = u64_stats_fetch_begin(&rxq_stats->syncp); + start = u64_stats_fetch_begin_irq(&rxq_stats->syncp); stats->pkts = rxq_stats->pkts; stats->bytes = rxq_stats->bytes; stats->errors = rxq_stats->csum_errors + rxq_stats->other_errors; stats->csum_errors = rxq_stats->csum_errors; stats->other_errors = rxq_stats->other_errors; - } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start)); } /** diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c index d1ea358a1fc06..8d3ec6c729cc7 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c @@ -98,14 +98,14 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats) unsigned int start; do { - start = u64_stats_fetch_begin(&txq_stats->syncp); + start = u64_stats_fetch_begin_irq(&txq_stats->syncp); stats->pkts = txq_stats->pkts; stats->bytes = txq_stats->bytes; stats->tx_busy = txq_stats->tx_busy; stats->tx_wake = txq_stats->tx_wake; stats->tx_dropped = txq_stats->tx_dropped; stats->big_frags_pkts = txq_stats->big_frags_pkts; - } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start)); } /** diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 850bfdf83d0a4..69ac205bbdbd0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3482,21 +3482,21 @@ static void nfp_net_stat64(struct net_device *netdev, unsigned int start; do { - start = u64_stats_fetch_begin(&r_vec->rx_sync); + start = u64_stats_fetch_begin_irq(&r_vec->rx_sync); data[0] = r_vec->rx_pkts; data[1] = r_vec->rx_bytes; data[2] = r_vec->rx_drops; - } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); + } while (u64_stats_fetch_retry_irq(&r_vec->rx_sync, start)); stats->rx_packets += data[0]; stats->rx_bytes += data[1]; stats->rx_dropped += data[2]; do { - start = u64_stats_fetch_begin(&r_vec->tx_sync); + start = u64_stats_fetch_begin_irq(&r_vec->tx_sync); data[0] = r_vec->tx_pkts; data[1] = r_vec->tx_bytes; data[2] = r_vec->tx_errors; - } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); + } while (u64_stats_fetch_retry_irq(&r_vec->tx_sync, start)); stats->tx_packets += data[0]; stats->tx_bytes += data[1]; stats->tx_errors += data[2]; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index ae72cde713438..62546d197bfd2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -483,7 +483,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) unsigned int start; do { - start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync); + start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].rx_sync); data[0] = nn->r_vecs[i].rx_pkts; tmp[0] = nn->r_vecs[i].hw_csum_rx_ok; tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok; @@ -491,10 +491,10 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) tmp[3] = nn->r_vecs[i].hw_csum_rx_error; tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail; tmp[5] = nn->r_vecs[i].hw_tls_rx; - } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start)); + } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].rx_sync, start)); do { - start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync); + start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].tx_sync); data[1] = nn->r_vecs[i].tx_pkts; data[2] = nn->r_vecs[i].tx_busy; tmp[6] = nn->r_vecs[i].hw_csum_tx; @@ -504,7 +504,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) tmp[10] = nn->r_vecs[i].hw_tls_tx; tmp[11] = nn->r_vecs[i].tls_tx_fallback; tmp[12] = nn->r_vecs[i].tls_tx_no_fallback; - } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start)); + } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].tx_sync, start)); data += NN_RVEC_PER_Q_STATS; diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 50572e0f1f529..84741715f6705 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -67,10 +67,10 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) unsigned int start; do { - start = u64_stats_fetch_begin(&ns->syncp); + start = u64_stats_fetch_begin_irq(&ns->syncp); stats->tx_bytes = ns->tx_bytes; stats->tx_packets = ns->tx_packets; - } while (u64_stats_fetch_retry(&ns->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ns->syncp, start)); } static int diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6eeef7a61927b..f1e263b2c2957 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2206,9 +2206,9 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, u64 value; do { - start = u64_stats_fetch_begin(&rxstats->syncp); + start = u64_stats_fetch_begin_irq(&rxstats->syncp); value = rxstats->msdu[tid]; - } while (u64_stats_fetch_retry(&rxstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); return value; } @@ -2272,9 +2272,9 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) u64 value; do { - start = u64_stats_fetch_begin(&rxstats->syncp); + start = u64_stats_fetch_begin_irq(&rxstats->syncp); value = rxstats->bytes; - } while (u64_stats_fetch_retry(&rxstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); return value; } diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 6e587feb705c4..58a7075084d17 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -1079,9 +1079,9 @@ static void mpls_get_stats(struct mpls_dev *mdev, p = per_cpu_ptr(mdev->stats, i); do { - start = u64_stats_fetch_begin(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); local = p->stats; - } while (u64_stats_fetch_retry(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += local.rx_packets; stats->rx_bytes += local.rx_bytes; From c5652d5d71cfcd09064942e82590cfde333bbbc5 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 26 Aug 2022 16:29:54 +0200 Subject: [PATCH 094/228] net: mac802154: Fix a condition in the receive path commit f0da47118c7e93cdbbc6fb403dd729a5f2c90ee3 upstream. Upon reception, a packet must be categorized, either it's destination is the host, or it is another host. A packet with no destination addressing fields may be valid in two situations: - the packet has no source field: only ACKs are built like that, we consider the host as the destination. - the packet has a valid source field: it is directed to the PAN coordinator, as for know we don't have this information we consider we are not the PAN coordinator. There was likely a copy/paste error made during a previous cleanup because the if clause is now containing exactly the same condition as in the switch case, which can never be true. In the past the destination address was used in the switch and the source address was used in the if, which matches what the spec says. Cc: stable@vger.kernel.org Fixes: ae531b9475f6 ("ieee802154: use ieee802154_addr instead of *_sa variants") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20220826142954.254853-1-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt Signed-off-by: Greg Kroah-Hartman --- net/mac802154/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index b8ce84618a55b..c439125ef2b91 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -44,7 +44,7 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, switch (mac_cb(skb)->dest.mode) { case IEEE802154_ADDR_NONE: - if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE) + if (hdr->source.mode != IEEE802154_ADDR_NONE) /* FIXME: check if we are PAN coordinator */ skb->pkt_type = PACKET_OTHERHOST; else From b2c973b52f149aed7ff3f363a53698fef1a843ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 27 Aug 2022 22:33:28 +0200 Subject: [PATCH 095/228] ALSA: hda/realtek: Add speaker AMP init for Samsung laptops with ALC298 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a2d57ebec1e15f0ac256eb8397e82b07adfaaacc upstream. Magic initialization sequence was extracted from Windows driver and cleaned up manually. Fixes internal speakers output. Link: https://bugzilla.kernel.org/show_bug.cgi?id=207423 Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1851518 Signed-off-by: Kacper Michajłow Cc: Link: https://lore.kernel.org/r/20220827203328.30363-1-kasper93@gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 63 +++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 600ba91f77031..45b8ebda284d9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4684,6 +4684,48 @@ static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, alc236_fixup_hp_micmute_led_vref(codec, fix, action); } +static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec, + const unsigned short coefs[2]) +{ + alc_write_coef_idx(codec, 0x23, coefs[0]); + alc_write_coef_idx(codec, 0x25, coefs[1]); + alc_write_coef_idx(codec, 0x26, 0xb011); +} + +struct alc298_samsung_amp_desc { + unsigned char nid; + unsigned short init_seq[2][2]; +}; + +static void alc298_fixup_samsung_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + int i, j; + static const unsigned short init_seq[][2] = { + { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 }, + { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 }, + { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e }, + { 0x41, 0x07 }, { 0x400, 0x1 } + }; + static const struct alc298_samsung_amp_desc amps[] = { + { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } }, + { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } } + }; + + if (action != HDA_FIXUP_ACT_INIT) + return; + + for (i = 0; i < ARRAY_SIZE(amps); i++) { + alc_write_coef_idx(codec, 0x22, amps[i].nid); + + for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++) + alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]); + + for (j = 0; j < ARRAY_SIZE(init_seq); j++) + alc298_samsung_write_coef_pack(codec, init_seq[j]); + } +} + #if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) @@ -6842,6 +6884,7 @@ enum { ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, + ALC298_FIXUP_SAMSUNG_AMP, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, @@ -8196,6 +8239,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led_micmute_vref, }, + [ALC298_FIXUP_SAMSUNG_AMP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_samsung_amp, + .chained = true, + .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET + }, [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8985,13 +9034,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), - SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), @@ -9351,7 +9400,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, - {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, + {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"}, {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, From 9b7a07fcc5d4918c4722a3522a14092efc8ed090 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 09:27:16 +0200 Subject: [PATCH 096/228] ALSA: seq: oss: Fix data-race for max_midi_devs access commit 22dec134dbfa825b963f8a1807ad19b943e46a56 upstream. ALSA OSS sequencer refers to a global variable max_midi_devs at creating a new port, storing it to its own field. Meanwhile this variable may be changed by other sequencer events at snd_seq_oss_midi_check_exit_port() in parallel, which may cause a data race. OTOH, this data race itself is almost harmless, as the access to the MIDI device is done via get_mdev() and it's protected with a refcount, hence its presence is guaranteed. Though, it's sill better to address the data-race from the code sanity POV, and this patch adds the proper spinlock for the protection. Reported-by: Abhishek Shah Cc: Link: https://lore.kernel.org/r/CAEHB2493pZRXs863w58QWnUTtv3HHfg85aYhLn5HJHCwxqtHQg@mail.gmail.com Link: https://lore.kernel.org/r/20220823072717.1706-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_midi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 1e3bf086f8671..07efb38f58ac1 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -270,7 +270,9 @@ snd_seq_oss_midi_clear_all(void) void snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) { + spin_lock_irq(®ister_lock); dp->max_mididev = max_midi_devs; + spin_unlock_irq(®ister_lock); } /* From 301be8985e8759a10bfb7c9b2b82c19d23bfce4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 09:27:17 +0200 Subject: [PATCH 097/228] ALSA: seq: Fix data-race at module auto-loading commit 3e7e04b747adea36f349715d9f0998eeebf15d72 upstream. It's been reported that there is a possible data-race accessing to the global card_requested[] array at ALSA sequencer core, which is used for determining whether to call request_module() for the card or not. This data race itself is almost harmless, as it might end up with one extra request_module() call for the already loaded module at most. But it's still better to fix. This patch addresses the possible data race of card_requested[] and client_requested[] arrays by replacing them with bitmask. It's an atomic operation and can work without locks. Reported-by: Abhishek Shah Cc: Link: https://lore.kernel.org/r/CAEHB24_ay6YzARpA1zgCsE7=H9CSJJzux618E=Ka4h0YdKn=qA@mail.gmail.com Link: https://lore.kernel.org/r/20220823072717.1706-2-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_clientmgr.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2e9d695d336c9..2d707afa1ef1c 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) spin_unlock_irqrestore(&clients_lock, flags); #ifdef CONFIG_MODULES if (!in_interrupt()) { - static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; - static char card_requested[SNDRV_CARDS]; + static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS); + static DECLARE_BITMAP(card_requested, SNDRV_CARDS); + if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { int idx; - if (!client_requested[clientid]) { - client_requested[clientid] = 1; + if (!test_and_set_bit(clientid, client_requested)) { for (idx = 0; idx < 15; idx++) { if (seq_client_load[idx] < 0) break; @@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) / SNDRV_SEQ_CLIENTS_PER_CARD; if (card < snd_ecards_limit) { - if (! card_requested[card]) { - card_requested[card] = 1; + if (!test_and_set_bit(card, card_requested)) snd_request_card(card); - } snd_seq_device_load_drivers(); } } From f9a0f49be767a45aa1dc7d846a2745bb7849268a Mon Sep 17 00:00:00 2001 From: Diego Santa Cruz Date: Thu, 16 Jun 2022 15:41:37 +0300 Subject: [PATCH 098/228] drm/i915/glk: ECS Liva Q2 needs GLK HDMI port timing quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 919bef7a106ade2bda73681bbc2f3678198f44fc upstream. The quirk added in upstream commit 90c3e2198777 ("drm/i915/glk: Add Quirk for GLK NUC HDMI port issues.") is also required on the ECS Liva Q2. Note: Would be nicer to figure out the extra delay required for the retimer without quirks, however don't know how to check for that. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/1326 Signed-off-by: Diego Santa Cruz Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220616124137.3184371-1-jani.nikula@intel.com (cherry picked from commit 08e9505fa8f9aa00072a47b6f234d89b6b27a89c) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/display/intel_quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c index 8a52b7a167746..407b096f53921 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.c +++ b/drivers/gpu/drm/i915/display/intel_quirks.c @@ -190,6 +190,9 @@ static struct intel_quirk intel_quirks[] = { /* ASRock ITX*/ { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, + /* ECS Liva Q2 */ + { 0x3185, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time }, + { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time }, }; void intel_init_quirks(struct drm_i915_private *i915) From 1787ec7dcc3761e040d0cd9896d3a40b4efac4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jun 2022 22:59:48 +0300 Subject: [PATCH 099/228] drm/i915: Skip wm/ddb readout for disabled pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0211c2a0ea600e25db3044daaeff4fe41c3ed6d9 upstream. The stuff programmed into the wm/ddb registers of planes on disabled pipes doesn't matter. So during readout just leave our software state tracking for those zeroed. This should avoid us trying too hard to clean up after whatever mess the VBIOS/GOP left in there. The actual hardware state will get cleaned up if/when we enable the pipe anyway. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5711 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220617195948.24007-1-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy (cherry picked from commit b183db8f4783ca2efc9b47734f15aad9477a108a) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_pm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1a27e4833adfa..9123baf723d82 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6638,7 +6638,10 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) enum plane_id plane_id; u8 slices; - skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal); + memset(&crtc_state->wm.skl.optimal, 0, + sizeof(crtc_state->wm.skl.optimal)); + if (crtc_state->hw.active) + skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal); crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal; memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe])); @@ -6649,6 +6652,9 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) struct skl_ddb_entry *ddb_uv = &crtc_state->wm.skl.plane_ddb_uv[plane_id]; + if (!crtc_state->hw.active) + continue; + skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe, plane_id, ddb_y, ddb_uv); From 309aea4b6b813f6678c3a547cfd7fe3a76ffa976 Mon Sep 17 00:00:00 2001 From: Mazin Al Haddad Date: Sun, 14 Aug 2022 04:52:12 +0300 Subject: [PATCH 100/228] tty: n_gsm: add sanity check for gsm->receive in gsm_receive_buf() commit f16c6d2e58a4c2b972efcf9eb12390ee0ba3befb upstream. A null pointer dereference can happen when attempting to access the "gsm->receive()" function in gsmld_receive_buf(). Currently, the code assumes that gsm->recieve is only called after MUX activation. Since the gsmld_receive_buf() function can be accessed without the need to initialize the MUX, the gsm->receive() function will not be set and a NULL pointer dereference will occur. Fix this by avoiding the call to "gsm->receive()" in case the function is not initialized by adding a sanity check. Call Trace: gsmld_receive_buf+0x1c2/0x2f0 drivers/tty/n_gsm.c:2861 tiocsti drivers/tty/tty_io.c:2293 [inline] tty_ioctl+0xa75/0x15d0 drivers/tty/tty_io.c:2692 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd Link: https://syzkaller.appspot.com/bug?id=bdf035c61447f8c6e0e6920315d577cb5cc35ac5 Fixes: 01aecd917114 ("tty: n_gsm: fix tty registration before control channel open") Cc: stable Reported-and-tested-by: syzbot+e3563f0c94e188366dbb@syzkaller.appspotmail.com Signed-off-by: Mazin Al Haddad Link: https://lore.kernel.org/r/20220814015211.84180-1-mazinalhaddad05@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index b89655f585f14..154697be11b0a 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2753,7 +2753,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, flags = *fp++; switch (flags) { case TTY_NORMAL: - gsm->receive(gsm, *cp); + if (gsm->receive) + gsm->receive(gsm, *cp); break; case TTY_OVERRUN: case TTY_BREAK: From 0baced0e0938f2895ceba54038eaf15ed91032e7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 4 Sep 2022 15:19:00 +0200 Subject: [PATCH 101/228] kbuild: Unify options for BTF generation for vmlinux and modules commit e27f05147bff21408c1b8410ad8e90cd286e7952 upstream. Using new PAHOLE_FLAGS variable to pass extra arguments to pahole for both vmlinux and modules BTF data generation. Adding new scripts/pahole-flags.sh script that detect and prints pahole options. [ fixed issues found by kernel test robot ] Signed-off-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20211029125729.70002-1-jolsa@kernel.org Signed-off-by: Greg Kroah-Hartman --- Makefile | 3 +++ scripts/Makefile.modfinal | 2 +- scripts/link-vmlinux.sh | 11 +---------- scripts/pahole-flags.sh | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 scripts/pahole-flags.sh diff --git a/Makefile b/Makefile index 9142dbf41f0d8..21316686af351 100644 --- a/Makefile +++ b/Makefile @@ -480,6 +480,8 @@ LZ4 = lz4c XZ = xz ZSTD = zstd +PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh) + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) NOSTDINC_FLAGS := @@ -534,6 +536,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL +export PAHOLE_FLAGS # Files to ignore in find ... statements diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index ff805777431ce..ce9661d968a3d 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -40,7 +40,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ if [ -f vmlinux ]; then \ - LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J --btf_base vmlinux $@; \ + LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ else \ printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ fi; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 3819a461465d8..57ef6accbb40f 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -211,7 +211,6 @@ vmlinux_link() gen_btf() { local pahole_ver - local extra_paholeopt= if ! [ -x "$(command -v ${PAHOLE})" ]; then echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" @@ -226,16 +225,8 @@ gen_btf() vmlinux_link ${1} - if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then - # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars - extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars" - fi - if [ "${pahole_ver}" -ge "121" ]; then - extra_paholeopt="${extra_paholeopt} --btf_gen_floats" - fi - info "BTF" ${2} - LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${extra_paholeopt} ${1} + LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1} # Create ${2} which contains just .BTF section but no symbols. Add # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh new file mode 100644 index 0000000000000..e6093adf4c06d --- /dev/null +++ b/scripts/pahole-flags.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +extra_paholeopt= + +if ! [ -x "$(command -v ${PAHOLE})" ]; then + exit 0 +fi + +pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') + +if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then + # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars + extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars" +fi +if [ "${pahole_ver}" -ge "121" ]; then + extra_paholeopt="${extra_paholeopt} --btf_gen_floats" +fi + +echo ${extra_paholeopt} From b775fbf532dc01ae53a6fc56168fd30cb4b0c658 Mon Sep 17 00:00:00 2001 From: Martin Rodriguez Reboredo Date: Sun, 4 Sep 2022 15:19:01 +0200 Subject: [PATCH 102/228] kbuild: Add skip_encoding_btf_enum64 option to pahole New pahole (version 1.24) generates by default new BTF_KIND_ENUM64 BTF tag, which is not supported by stable kernel. As a result the kernel with CONFIG_DEBUG_INFO_BTF option will fail to compile with following error: BTFIDS vmlinux FAILED: load BTF from vmlinux: Invalid argument New pahole provides --skip_encoding_btf_enum64 option to skip BTF_KIND_ENUM64 generation and produce BTF supported by stable kernel. Adding this option to scripts/pahole-flags.sh. This change does not have equivalent commit in linus tree, because linus tree has support for BTF_KIND_ENUM64 tag, so it does not need to be disabled. Signed-off-by: Martin Rodriguez Reboredo Signed-off-by: Jiri Olsa Signed-off-by: Greg Kroah-Hartman --- scripts/pahole-flags.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh index e6093adf4c06d..7acee326aa6c9 100644 --- a/scripts/pahole-flags.sh +++ b/scripts/pahole-flags.sh @@ -17,4 +17,8 @@ if [ "${pahole_ver}" -ge "121" ]; then extra_paholeopt="${extra_paholeopt} --btf_gen_floats" fi +if [ "${pahole_ver}" -ge "124" ]; then + extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_enum64" +fi + echo ${extra_paholeopt} From 9d6a2d022010196f07d1f8b7ddcd248726dfe2d5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Sep 2022 14:07:00 +0200 Subject: [PATCH 103/228] usb: dwc3: fix PHY disable sequence commit d2ac7bef95c9ead307801ccb6cb6dfbeb14247bf upstream. Generic PHYs must be powered-off before they can be tore down. Similarly, suspending legacy PHYs after having powered them off makes no sense. Fix the dwc3_core_exit() (e.g. called during suspend) and open-coded dwc3_probe() error-path sequences that got this wrong. Note that this makes dwc3_core_exit() match the dwc3_core_init() error path with respect to powering off the PHYs. Fixes: 03c1fd622f72 ("usb: dwc3: core: add phy cleanup for probe error handling") Fixes: c499ff71ff2a ("usb: dwc3: core: re-factor init and exit paths") Cc: stable@vger.kernel.org # 4.8 Reviewed-by: Andrew Halaney Reviewed-by: Matthias Kaehlcke Reviewed-by: Manivannan Sadhasivam Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220804151001.23612-2-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman [ johan: adjust context to 5.15 ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index cfac5503aa662..9c24cf46b9a08 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -731,15 +731,16 @@ static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + phy_power_off(dwc->usb2_generic_phy); + phy_power_off(dwc->usb3_generic_phy); + usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); reset_control_assert(dwc->reset); } @@ -1662,16 +1663,16 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_debugfs_exit(dwc); dwc3_event_buffers_cleanup(dwc); - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); phy_power_off(dwc->usb2_generic_phy); phy_power_off(dwc->usb3_generic_phy); + usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy); + phy_exit(dwc->usb2_generic_phy); + phy_exit(dwc->usb3_generic_phy); + dwc3_ulpi_exit(dwc); err4: From 121c6e37da76f07385d490ee525ab3231f2c6b86 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Sep 2022 14:07:01 +0200 Subject: [PATCH 104/228] usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup commit a872ab303d5ddd4c965f9cd868677781a33ce35a upstream. The Qualcomm dwc3 runtime-PM implementation checks the xhci platform-device pointer in the wakeup-interrupt handler to determine whether the controller is in host mode and if so triggers a resume. After a role switch in OTG mode the xhci platform-device would have been freed and the next wakeup from runtime suspend would access the freed memory. Note that role switching is executed from a freezable workqueue, which guarantees that the pointer is stable during suspend. Also note that runtime PM has been broken since commit 2664deb09306 ("usb: dwc3: qcom: Honor wakeup enabled/disabled state"), which incidentally also prevents this issue from being triggered. Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver") Cc: stable@vger.kernel.org # 4.18 Reviewed-by: Matthias Kaehlcke Reviewed-by: Manivannan Sadhasivam Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220804151001.23612-5-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman [ johan: adjust context for 5.15 ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 14 +++++++++++++- drivers/usb/dwc3/host.c | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 873bf5041117f..d0352daab0128 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -296,6 +296,14 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) icc_put(qcom->icc_path_apps); } +/* Only usable in contexts where the role can not change. */ +static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) +{ + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); + + return dwc->xhci; +} + static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) { if (qcom->hs_phy_irq) { @@ -411,7 +419,11 @@ static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) if (qcom->pm_suspended) return IRQ_HANDLED; - if (dwc->xhci) + /* + * This is safe as role switching is done from a freezable workqueue + * and the wakeup interrupts are disabled as part of resume. + */ + if (dwc3_qcom_is_host(qcom)) pm_runtime_resume(&dwc->xhci->dev); return IRQ_HANDLED; diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index f29a264635aa1..2078e9d702923 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -130,4 +130,5 @@ int dwc3_host_init(struct dwc3 *dwc) void dwc3_host_exit(struct dwc3 *dwc) { platform_device_unregister(dwc->xhci); + dwc->xhci = NULL; } From 55d328924347dfb315fe096efdb59567a9a7a362 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Sep 2022 14:07:02 +0200 Subject: [PATCH 105/228] usb: dwc3: disable USB core PHY management commit 6000b8d900cd5f52fbcd0776d0cc396e88c8c2ea upstream. The dwc3 driver manages its PHYs itself so the USB core PHY management needs to be disabled. Use the struct xhci_plat_priv hack added by commits 46034a999c07 ("usb: host: xhci-plat: add platform data support") and f768e718911e ("usb: host: xhci-plat: add priv quirk for skip PHY initialization") to propagate the setting for now. Fixes: 4e88d4c08301 ("usb: add a flag to skip PHY initialization to struct usb_hcd") Fixes: 178a0bce05cb ("usb: core: hcd: integrate the PHY wrapper into the HCD core") Tested-by: Matthias Kaehlcke Cc: stable Reviewed-by: Matthias Kaehlcke Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220825131836.19769-1-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman [ johan: adjust context to 5.15 ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/host.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 2078e9d702923..85165a972076d 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -10,8 +10,13 @@ #include #include +#include "../host/xhci-plat.h" #include "core.h" +static const struct xhci_plat_priv dwc3_xhci_plat_priv = { + .quirks = XHCI_SKIP_PHY_INIT, +}; + static int dwc3_host_get_irq(struct dwc3 *dwc) { struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); @@ -87,6 +92,11 @@ int dwc3_host_init(struct dwc3 *dwc) goto err; } + ret = platform_device_add_data(xhci, &dwc3_xhci_plat_priv, + sizeof(dwc3_xhci_plat_priv)); + if (ret) + goto err; + memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); if (dwc->usb3_lpm_capable) From e0923b4f38df5f9c2c5d511227e23873d7293906 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Sep 2022 14:21:26 +0200 Subject: [PATCH 106/228] USB: serial: ch341: fix lost character on LCR updates commit 8e83622ae7ca481c76c8fd9579877f6abae64ca2 upstream. Disable LCR updates for pre-0x30 devices which use a different (unknown) protocol for line control and where the current register write causes the next received character to be lost. Note that updating LCR using the INIT command has no effect on these devices either. Reported-by: Jonathan Woithe Tested-by: Jonathan Woithe Link: https://lore.kernel.org/r/Ys1iPTfiZRWj2gXs@marvin.atrad.com.au Fixes: 4e46c410e050 ("USB: serial: ch341: reinitialize chip on reconfiguration") Fixes: 55fa15b5987d ("USB: serial: ch341: fix baud rate and line-control handling") Cc: stable@vger.kernel.org # 4.10 Signed-off-by: Johan Hovold [ johan: adjust context to 5.15 ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index b5a1864e9cfdc..b787533aec645 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -97,7 +97,10 @@ struct ch341_private { u8 mcr; u8 msr; u8 lcr; + unsigned long quirks; + u8 version; + unsigned long break_end; }; @@ -271,6 +274,9 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev, * (stop bits, parity and word length). Version 0x30 and above use * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. */ + if (priv->version < 0x30) + return 0; + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr); if (r) @@ -323,7 +329,9 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size); if (r < 0) goto out; - dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]); + + priv->version = buffer[0]; + dev_dbg(&dev->dev, "Chip version: 0x%02x\n", priv->version); r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0); if (r < 0) From e1779c25e48bc9eb4edb47d2c8e04459ef19d681 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Sep 2022 14:21:27 +0200 Subject: [PATCH 107/228] USB: serial: ch341: fix disabled rx timer on older devices commit 41ca302a697b64a3dab4676e01d0d11bb184737d upstream. At least one older CH341 appears to have the RX timer enable bit inverted so that setting it disables the RX timer and prevents the FIFO from emptying until it is full. Only set the RX timer enable bit for devices with version newer than 0x27 (even though this probably affects all pre-0x30 devices). Reported-by: Jonathan Woithe Tested-by: Jonathan Woithe Link: https://lore.kernel.org/r/Ys1iPTfiZRWj2gXs@marvin.atrad.com.au Fixes: 4e46c410e050 ("USB: serial: ch341: reinitialize chip on reconfiguration") Cc: stable@vger.kernel.org # 4.10 Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index b787533aec645..752daa952abd6 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -259,8 +259,12 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev, /* * CH341A buffers data until a full endpoint-size packet (32 bytes) * has been received unless bit 7 is set. + * + * At least one device with version 0x27 appears to have this bit + * inverted. */ - val |= BIT(7); + if (priv->version > 0x27) + val |= BIT(7); r = ch341_control_out(dev, CH341_REQ_WRITE_REG, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, From bcecd2ee19efeae47519e0fd4126559feeea129e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Sep 2022 12:28:08 +0200 Subject: [PATCH 108/228] Linux 5.15.66 Link: https://lore.kernel.org/r/20220906132821.713989422@linuxfoundation.org Tested-by: Florian Fainelli Tested-by: Linux Kernel Functional Testing Tested-by: Shuah Khan Tested-by: Guenter Roeck Tested-by: Sudip Mukherjee Tested-by: Bagas Sanjaya Tested-by: Ron Economos Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 21316686af351..4e747c99e7e07 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 15 -SUBLEVEL = 65 +SUBLEVEL = 66 EXTRAVERSION = NAME = Trick or Treat From 096e34b05a439f0e607529d9404be3c3f59d2064 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Sep 2022 12:30:36 +0200 Subject: [PATCH 109/228] kbuild: fix up permissions on scripts/pahole-flags.sh Commit b775fbf532dc ("kbuild: Add skip_encoding_btf_enum64 option to pahole") created the file scripts/pahole-flags.sh, but due to a mismatch between patch and quilt and git, the execute permissions did not get set properly. Fix that up. Reported-by: Florian Fainelli Reported-by: Sudip Mukherjee Fixes: b775fbf532dc ("kbuild: Add skip_encoding_btf_enum64 option to pahole") Signed-off-by: Greg Kroah-Hartman --- scripts/pahole-flags.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/pahole-flags.sh diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh old mode 100644 new mode 100755 From e1ad7a011591d4a508a08e180ae0471224fcc17c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Sep 2022 12:32:54 +0200 Subject: [PATCH 110/228] Linux 5.15.67 Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4e747c99e7e07..eca45b7be9c1e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 15 -SUBLEVEL = 66 +SUBLEVEL = 67 EXTRAVERSION = NAME = Trick or Treat From 6427605fa7815b312b3a06f7d0299933b1e092e3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 18 May 2022 17:43:42 -0700 Subject: [PATCH 111/228] net: wwan: iosm: remove pointless null check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dbbc7d04c549a43ad343c69e17b27a57e2102041 upstream. GCC 12 warns: drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c: In function ‘ipc_protocol_dl_td_process’: drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c:406:13: warning: the comparison will always evaluate as ‘true’ for the address of ‘cb’ will never be NULL [-Waddress] 406 | if (!IPC_CB(skb)) { | ^ Indeed the check seems entirely pointless. Hopefully the other validation checks will catch if the cb is bad, but it can't be NULL. Reviewed-by: M Chetan Kumar Link: https://lore.kernel.org/r/20220519004342.2109832-1-kuba@kernel.org Signed-off-by: Jakub Kicinski Cc: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c index c6b032f95d2e4..4627847c6daab 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c +++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c @@ -372,8 +372,6 @@ bool ipc_protocol_dl_td_prepare(struct iosm_protocol *ipc_protocol, struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol, struct ipc_pipe *pipe) { - u32 tail = - le32_to_cpu(ipc_protocol->p_ap_shm->tail_array[pipe->pipe_nr]); struct ipc_protocol_td *p_td; struct sk_buff *skb; @@ -403,14 +401,6 @@ struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol, goto ret; } - if (!IPC_CB(skb)) { - dev_err(ipc_protocol->dev, "pipe# %d, tail: %d skb_cb is NULL", - pipe->pipe_nr, tail); - ipc_pcie_kfree_skb(ipc_protocol->pcie, skb); - skb = NULL; - goto ret; - } - if (p_td->buffer.address != IPC_CB(skb)->mapping) { dev_err(ipc_protocol->dev, "invalid buf=%llx or skb=%p", (unsigned long long)p_td->buffer.address, skb->data); From ee06f08139e7feacb6116fc9ca8de902e2c63d65 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 22 Aug 2022 19:20:33 +0200 Subject: [PATCH 112/228] efi: libstub: Disable struct randomization commit 1a3887924a7e6edd331be76da7bf4c1e8eab4b1e upstream. The EFI stub is a wrapper around the core kernel that makes it look like a EFI compatible PE/COFF application to the EFI firmware. EFI applications run on top of the EFI runtime, which is heavily based on so-called protocols, which are struct types consisting [mostly] of function pointer members that are instantiated and recorded in a protocol database. These structs look like the ideal randomization candidates to the randstruct plugin (as they only carry function pointers), but of course, these protocols are contracts between the firmware that exposes them, and the EFI applications (including our stubbed kernel) that invoke them. This means that struct randomization for EFI protocols is not a great idea, and given that the stub shares very little data with the core kernel that is represented as a randomizable struct, we're better off just disabling it completely here. Cc: # v4.14+ Reported-by: Daniel Marth Tested-by: Daniel Marth Signed-off-by: Ard Biesheuvel Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/libstub/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index d0537573501e9..2c67f71f23753 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -37,6 +37,13 @@ KBUILD_CFLAGS := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \ $(call cc-option,-fno-addrsig) \ -D__DISABLE_EXPORTS +# +# struct randomization only makes sense for Linux internal types, which the EFI +# stub code never touches, so let's turn off struct randomization for the stub +# altogether +# +KBUILD_CFLAGS := $(filter-out $(RANDSTRUCT_CFLAGS), $(KBUILD_CFLAGS)) + # remove SCS flags from all objects in this directory KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_SCS), $(KBUILD_CFLAGS)) # disable LTO From dd291e070be0eca8807476b022bda00c891d9066 Mon Sep 17 00:00:00 2001 From: Hyunwoo Kim Date: Wed, 7 Sep 2022 09:07:14 -0700 Subject: [PATCH 113/228] efi: capsule-loader: Fix use-after-free in efi_capsule_write commit 9cb636b5f6a8cc6d1b50809ec8f8d33ae0c84c95 upstream. A race condition may occur if the user calls close() on another thread during a write() operation on the device node of the efi capsule. This is a race condition that occurs between the efi_capsule_write() and efi_capsule_flush() functions of efi_capsule_fops, which ultimately results in UAF. So, the page freeing process is modified to be done in efi_capsule_release() instead of efi_capsule_flush(). Cc: # v4.9+ Signed-off-by: Hyunwoo Kim Link: https://lore.kernel.org/all/20220907102920.GA88602@ubuntu/ Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/capsule-loader.c | 31 ++++++--------------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 4dde8edd53b62..3e8d4b51a8140 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -242,29 +242,6 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, return ret; } -/** - * efi_capsule_flush - called by file close or file flush - * @file: file pointer - * @id: not used - * - * If a capsule is being partially uploaded then calling this function - * will be treated as upload termination and will free those completed - * buffer pages and -ECANCELED will be returned. - **/ -static int efi_capsule_flush(struct file *file, fl_owner_t id) -{ - int ret = 0; - struct capsule_info *cap_info = file->private_data; - - if (cap_info->index > 0) { - pr_err("capsule upload not complete\n"); - efi_free_all_buff_pages(cap_info); - ret = -ECANCELED; - } - - return ret; -} - /** * efi_capsule_release - called by file close * @inode: not used @@ -277,6 +254,13 @@ static int efi_capsule_release(struct inode *inode, struct file *file) { struct capsule_info *cap_info = file->private_data; + if (cap_info->index > 0 && + (cap_info->header.headersize == 0 || + cap_info->count < cap_info->total_size)) { + pr_err("capsule upload not complete\n"); + efi_free_all_buff_pages(cap_info); + } + kfree(cap_info->pages); kfree(cap_info->phys); kfree(file->private_data); @@ -324,7 +308,6 @@ static const struct file_operations efi_capsule_fops = { .owner = THIS_MODULE, .open = efi_capsule_open, .write = efi_capsule_write, - .flush = efi_capsule_flush, .release = efi_capsule_release, .llseek = no_llseek, }; From 44b402da7b243ba41560577e84357226ed4a7778 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 15 Aug 2022 09:37:37 +0200 Subject: [PATCH 114/228] wifi: iwlegacy: 4965: corrected fix for potential off-by-one overflow in il4965_rs_fill_link_cmd() commit 6d0ef7241553f3553a0a2764c69b07892705924c upstream. This reverts commit a8eb8e6f7159c7c20c0ddac428bde3d110890aa7 as it can cause invalid link quality command sent to the firmware and address the off-by-one issue by fixing condition of while loop. Cc: stable@vger.kernel.org Fixes: a8eb8e6f7159 ("wifi: iwlegacy: 4965: fix potential off-by-one overflow in il4965_rs_fill_link_cmd()") Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220815073737.GA999388@wp.pl Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlegacy/4965-rs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c index 532e3b91777d9..150805aec4071 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c @@ -2403,7 +2403,7 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta, /* Repeat initial/next rate. * For legacy IL_NUMBER_TRY == 1, this loop will not execute. * For HT IL_HT_NUMBER_TRY == 3, this executes twice. */ - while (repeat_rate > 0) { + while (repeat_rate > 0 && idx < (LINK_QUAL_MAX_RETRY_NUM - 1)) { if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) ant_toggle_cnt++; @@ -2422,8 +2422,6 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta, cpu_to_le32(new_rate); repeat_rate--; idx++; - if (idx >= LINK_QUAL_MAX_RETRY_NUM) - goto out; } il4965_rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, @@ -2468,7 +2466,6 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta, repeat_rate--; } -out: lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; From 7c6333411acf23e98a259cf104ab858c1ccab74f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 31 Aug 2022 09:46:12 -0700 Subject: [PATCH 115/228] fs: only do a memory barrier for the first set_buffer_uptodate() commit 2f79cdfe58c13949bbbb65ba5926abfe9561d0ec upstream. Commit d4252071b97d ("add barriers to buffer_uptodate and set_buffer_uptodate") added proper memory barriers to the buffer head BH_Uptodate bit, so that anybody who tests a buffer for being up-to-date will be guaranteed to actually see initialized state. However, that commit didn't _just_ add the memory barrier, it also ended up dropping the "was it already set" logic that the BUFFER_FNS() macro had. That's conceptually the right thing for a generic "this is a memory barrier" operation, but in the case of the buffer contents, we really only care about the memory barrier for the _first_ time we set the bit, in that the only memory ordering protection we need is to avoid anybody seeing uninitialized memory contents. Any other access ordering wouldn't be about the BH_Uptodate bit anyway, and would require some other proper lock (typically BH_Lock or the folio lock). A reader that races with somebody invalidating the buffer head isn't an issue wrt the memory ordering, it's a serialization issue. Now, you'd think that the buffer head operations don't matter in this day and age (and I certainly thought so), but apparently some loads still end up being heavy users of buffer heads. In particular, the kernel test robot reported that not having this bit access optimization in place caused a noticeable direct IO performance regression on ext4: fxmark.ssd_ext4_no_jnl_DWTL_54_directio.works/sec -26.5% regression although you presumably need a fast disk and a lot of cores to actually notice. Link: https://lore.kernel.org/all/Yw8L7HTZ%2FdE2%2Fo9C@xsang-OptiPlex-9020/ Reported-by: kernel test robot Tested-by: Fengwei Yin Cc: Mikulas Patocka Cc: Matthew Wilcox (Oracle) Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/buffer_head.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index c841367ff8c95..25b4263d66d70 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -136,6 +136,17 @@ BUFFER_FNS(Defer_Completion, defer_completion) static __always_inline void set_buffer_uptodate(struct buffer_head *bh) { + /* + * If somebody else already set this uptodate, they will + * have done the memory barrier, and a reader will thus + * see *some* valid buffer state. + * + * Any other serialization (with IO errors or whatever that + * might clear the bit) has to come from other state (eg BH_Lock). + */ + if (test_bit(BH_Uptodate, &bh->b_state)) + return; + /* * make it consistent with folio_mark_uptodate * pairs with smp_load_acquire in buffer_uptodate From 625c78e1ae355474ea47b980337a9c3ca4195814 Mon Sep 17 00:00:00 2001 From: Yee Lee Date: Tue, 6 Sep 2022 15:03:06 +0800 Subject: [PATCH 116/228] Revert "mm: kmemleak: take a full lowmem check in kmemleak_*_phys()" This reverts commit 23c2d497de21f25898fbea70aeb292ab8acc8c94. Commit 23c2d497de21 ("mm: kmemleak: take a full lowmem check in kmemleak_*_phys()") brought false leak alarms on some archs like arm64 that does not init pfn boundary in early booting. The final solution lands on linux-6.0: commit 0c24e061196c ("mm: kmemleak: add rbtree and store physical address for objects allocated with PA"). Revert this commit before linux-6.0. The original issue of invalid PA can be mitigated by additional check in devicetree. The false alarm report is as following: Kmemleak output: (Qemu/arm64) unreferenced object 0xffff0000c0170a00 (size 128): comm "swapper/0", pid 1, jiffies 4294892404 (age 126.208s) hex dump (first 32 bytes): 62 61 73 65 00 00 00 00 00 00 00 00 00 00 00 00 base............ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<(____ptrval____)>] __kmalloc_track_caller+0x1b0/0x2e4 [<(____ptrval____)>] kstrdup_const+0x8c/0xc4 [<(____ptrval____)>] kvasprintf_const+0xbc/0xec [<(____ptrval____)>] kobject_set_name_vargs+0x58/0xe4 [<(____ptrval____)>] kobject_add+0x84/0x100 [<(____ptrval____)>] __of_attach_node_sysfs+0x78/0xec [<(____ptrval____)>] of_core_init+0x68/0x104 [<(____ptrval____)>] driver_init+0x28/0x48 [<(____ptrval____)>] do_basic_setup+0x14/0x28 [<(____ptrval____)>] kernel_init_freeable+0x110/0x178 [<(____ptrval____)>] kernel_init+0x20/0x1a0 [<(____ptrval____)>] ret_from_fork+0x10/0x20 This pacth is also applicable to linux-5.17.y/linux-5.18.y/linux-5.19.y Cc: Signed-off-by: Yee Lee Signed-off-by: Greg Kroah-Hartman --- mm/kmemleak.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 859303aae1809..b78861b8e0139 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1125,7 +1125,7 @@ EXPORT_SYMBOL(kmemleak_no_scan); void __ref kmemleak_alloc_phys(phys_addr_t phys, size_t size, int min_count, gfp_t gfp) { - if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) + if (!IS_ENABLED(CONFIG_HIGHMEM) || PHYS_PFN(phys) < max_low_pfn) kmemleak_alloc(__va(phys), size, min_count, gfp); } EXPORT_SYMBOL(kmemleak_alloc_phys); @@ -1139,7 +1139,7 @@ EXPORT_SYMBOL(kmemleak_alloc_phys); */ void __ref kmemleak_free_part_phys(phys_addr_t phys, size_t size) { - if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) + if (!IS_ENABLED(CONFIG_HIGHMEM) || PHYS_PFN(phys) < max_low_pfn) kmemleak_free_part(__va(phys), size); } EXPORT_SYMBOL(kmemleak_free_part_phys); @@ -1151,7 +1151,7 @@ EXPORT_SYMBOL(kmemleak_free_part_phys); */ void __ref kmemleak_not_leak_phys(phys_addr_t phys) { - if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) + if (!IS_ENABLED(CONFIG_HIGHMEM) || PHYS_PFN(phys) < max_low_pfn) kmemleak_not_leak(__va(phys)); } EXPORT_SYMBOL(kmemleak_not_leak_phys); @@ -1163,7 +1163,7 @@ EXPORT_SYMBOL(kmemleak_not_leak_phys); */ void __ref kmemleak_ignore_phys(phys_addr_t phys) { - if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) + if (!IS_ENABLED(CONFIG_HIGHMEM) || PHYS_PFN(phys) < max_low_pfn) kmemleak_ignore(__va(phys)); } EXPORT_SYMBOL(kmemleak_ignore_phys); From 8179f0e08578ec4a1db1acf3ab8fac826864ed50 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Thu, 7 Jul 2022 15:08:01 -0400 Subject: [PATCH 117/228] scsi: qla2xxx: Disable ATIO interrupt coalesce for quad port ISP27XX [ Upstream commit 53661ded2460b414644532de6b99bd87f71987e9 ] This partially reverts commit d2b292c3f6fd ("scsi: qla2xxx: Enable ATIO interrupt handshake for ISP27XX") For some workloads where the host sends a batch of commands and then pauses, ATIO interrupt coalesce can cause some incoming ATIO entries to be ignored for extended periods of time, resulting in slow performance, timeouts, and aborted commands. Disable interrupt coalesce and re-enable the dedicated ATIO MSI-X interrupt. Link: https://lore.kernel.org/r/97dcf365-89ff-014d-a3e5-1404c6af511c@cybernetics.com Reviewed-by: Himanshu Madhani Reviewed-by: Nilesh Javali Signed-off-by: Tony Battersby Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_target.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 7ab3c9e4d4783..b86f6e1f21b5c 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -6961,14 +6961,8 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha) if (ha->flags.msix_enabled) { if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { - if (IS_QLA2071(ha)) { - /* 4 ports Baker: Enable Interrupt Handshake */ - icb->msix_atio = 0; - icb->firmware_options_2 |= cpu_to_le32(BIT_26); - } else { - icb->msix_atio = cpu_to_le16(msix->entry); - icb->firmware_options_2 &= cpu_to_le32(~BIT_26); - } + icb->msix_atio = cpu_to_le16(msix->entry); + icb->firmware_options_2 &= cpu_to_le32(~BIT_26); ql_dbg(ql_dbg_init, vha, 0xf072, "Registering ICB vector 0x%x for atio que.\n", msix->entry); From bbfd857abbd25cd168f643d154f33b3ce045ec6e Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Tue, 2 Aug 2022 15:18:49 +0800 Subject: [PATCH 118/228] scsi: megaraid_sas: Fix double kfree() [ Upstream commit 8c499e49240bd93628368c3588975cfb94169b8b ] When allocating log_to_span fails, kfree(instance->ctrl_context) is called twice. Remove redundant call. Link: https://lore.kernel.org/r/1659424729-46502-1-git-send-email-kanie@linux.alibaba.com Acked-by: Sumit Saxena Signed-off-by: Guixin Liu Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index eb5ceb75a15ec..056837849ead5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -5279,7 +5279,6 @@ megasas_alloc_fusion_context(struct megasas_instance *instance) if (!fusion->log_to_span) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); - kfree(instance->ctrl_context); return -ENOMEM; } } From 1f574fbe9c2b831a8c3156260842a7abd280d59f Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 19 Aug 2022 15:28:34 +0800 Subject: [PATCH 119/228] drm/gem: Fix GEM handle release errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ea2aa97ca37a9044ade001aef71dbc06318e8d44 ] Currently we are assuming a one to one mapping between dmabuf and GEM handle when releasing GEM handles. But that is not always true, since we would create extra handles for the GEM obj in cases like gem_open() and getfb{,2}(). A similar issue was reported at: https://lore.kernel.org/all/20211105083308.392156-1-jay.xu@rock-chips.com/ Another problem is that the imported dmabuf might not always have gem_obj->dma_buf set, which would cause leaks in drm_gem_remove_prime_handles(). Let's fix these for now by using handle to find the exact map to remove. Signed-off-by: Jeffy Chen Reviewed-by: Christian König Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220819072834.17888-1-jeffy.chen@rock-chips.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_gem.c | 17 +---------------- drivers/gpu/drm/drm_internal.h | 4 ++-- drivers/gpu/drm/drm_prime.c | 20 ++++++++++++-------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 6410563a9cb6f..dbd19a34b517b 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -167,21 +167,6 @@ void drm_gem_private_object_init(struct drm_device *dev, } EXPORT_SYMBOL(drm_gem_private_object_init); -static void -drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) -{ - /* - * Note: obj->dma_buf can't disappear as long as we still hold a - * handle reference in obj->handle_count. - */ - mutex_lock(&filp->prime.lock); - if (obj->dma_buf) { - drm_prime_remove_buf_handle_locked(&filp->prime, - obj->dma_buf); - } - mutex_unlock(&filp->prime.lock); -} - /** * drm_gem_object_handle_free - release resources bound to userspace handles * @obj: GEM object to clean up. @@ -252,7 +237,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) if (obj->funcs->close) obj->funcs->close(obj, file_priv); - drm_gem_remove_prime_handles(obj, file_priv); + drm_prime_remove_buf_handle(&file_priv->prime, id); drm_vma_node_revoke(&obj->vma_node, file_priv); drm_gem_object_handle_put_unlocked(obj); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 17f3548c8ed25..d05e6a5b66873 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -74,8 +74,8 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); -void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, - struct dma_buf *dma_buf); +void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, + uint32_t handle); /* drm_drv.c */ struct drm_minor *drm_minor_acquire(unsigned int minor_id); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index d6c7f4f9a7a29..a350310b65d89 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -187,29 +187,33 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri return -ENOENT; } -void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, - struct dma_buf *dma_buf) +void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, + uint32_t handle) { struct rb_node *rb; - rb = prime_fpriv->dmabufs.rb_node; + mutex_lock(&prime_fpriv->lock); + + rb = prime_fpriv->handles.rb_node; while (rb) { struct drm_prime_member *member; - member = rb_entry(rb, struct drm_prime_member, dmabuf_rb); - if (member->dma_buf == dma_buf) { + member = rb_entry(rb, struct drm_prime_member, handle_rb); + if (member->handle == handle) { rb_erase(&member->handle_rb, &prime_fpriv->handles); rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs); - dma_buf_put(dma_buf); + dma_buf_put(member->dma_buf); kfree(member); - return; - } else if (member->dma_buf < dma_buf) { + break; + } else if (member->handle < handle) { rb = rb->rb_right; } else { rb = rb->rb_left; } } + + mutex_unlock(&prime_fpriv->lock); } void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) From c15c2c2c08964fd99d3366f80742129f8ae28eaa Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Fri, 12 Aug 2022 13:38:34 +0800 Subject: [PATCH 120/228] drm/amdgpu: Move psp_xgmi_terminate call from amdgpu_xgmi_remove_device to psp_hw_fini [ Upstream commit 9d705d7741ae70764f3d6d87e67fad3b5c30ffd0 ] V1: The amdgpu_xgmi_remove_device function will send unload command to psp through psp ring to terminate xgmi, but psp ring has been destroyed in psp_hw_fini. V2: 1. Change the commit title. 2. Restore amdgpu_xgmi_remove_device to its original calling location. Move psp_xgmi_terminate call from amdgpu_xgmi_remove_device to psp_hw_fini. Signed-off-by: YiPeng Chai Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 57e9932d8a04e..5b41c29f3ed50 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -2729,6 +2729,9 @@ static int psp_hw_fini(void *handle) psp_rap_terminate(psp); psp_dtm_terminate(psp); psp_hdcp_terminate(psp); + + if (adev->gmc.xgmi.num_physical_nodes > 1) + psp_xgmi_terminate(psp); } psp_asd_unload(psp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index a799e0b1ff736..ce0b9cb61f582 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -723,7 +723,7 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev) amdgpu_put_xgmi_hive(hive); } - return psp_xgmi_terminate(&adev->psp); + return 0; } static int amdgpu_xgmi_ras_late_init(struct amdgpu_device *adev) From 622a557b28b718d4da92ff3504d83af2310324d2 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Thu, 18 Aug 2022 10:47:09 +0800 Subject: [PATCH 121/228] drm/amdgpu: Check num_gfx_rings for gfx v9_0 rb setup. [ Upstream commit c351938350ab9b5e978dede2c321da43de7eb70c ] No need to set up rb when no gfx rings. Signed-off-by: Candice Li Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index db27fcf87cd04..16cbae04078ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2624,7 +2624,8 @@ static void gfx_v9_0_constants_init(struct amdgpu_device *adev) gfx_v9_0_tiling_mode_table_init(adev); - gfx_v9_0_setup_rb(adev); + if (adev->gfx.num_gfx_rings) + gfx_v9_0_setup_rb(adev); gfx_v9_0_get_cu_info(adev, &adev->gfx.cu_info); adev->gfx.config.db_debug2 = RREG32_SOC15(GC, 0, mmDB_DEBUG2); From 5a7a5b2edac4b05abd744eeaebda46d9dacd952d Mon Sep 17 00:00:00 2001 From: Zhenneng Li Date: Thu, 11 Aug 2022 15:25:40 +0800 Subject: [PATCH 122/228] drm/radeon: add a force flush to delay work when radeon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f461950fdc374a3ada5a63c669d997de4600dffe ] Although radeon card fence and wait for gpu to finish processing current batch rings, there is still a corner case that radeon lockup work queue may not be fully flushed, and meanwhile the radeon_suspend_kms() function has called pci_set_power_state() to put device in D3hot state. Per PCI spec rev 4.0 on 5.3.1.4.1 D3hot State. > Configuration and Message requests are the only TLPs accepted by a Function in > the D3hot state. All other received Requests must be handled as Unsupported Requests, > and all received Completions may optionally be handled as Unexpected Completions. This issue will happen in following logs: Unable to handle kernel paging request at virtual address 00008800e0008010 CPU 0 kworker/0:3(131): Oops 0 pc = [] ra = [] ps = 0000 Tainted: G W pc is at si_gpu_check_soft_reset+0x3c/0x240 ra is at si_dma_is_lockup+0x34/0xd0 v0 = 0000000000000000 t0 = fff08800e0008010 t1 = 0000000000010000 t2 = 0000000000008010 t3 = fff00007e3c00000 t4 = fff00007e3c00258 t5 = 000000000000ffff t6 = 0000000000000001 t7 = fff00007ef078000 s0 = fff00007e3c016e8 s1 = fff00007e3c00000 s2 = fff00007e3c00018 s3 = fff00007e3c00000 s4 = fff00007fff59d80 s5 = 0000000000000000 s6 = fff00007ef07bd98 a0 = fff00007e3c00000 a1 = fff00007e3c016e8 a2 = 0000000000000008 a3 = 0000000000000001 a4 = 8f5c28f5c28f5c29 a5 = ffffffff810f4338 t8 = 0000000000000275 t9 = ffffffff809b66f8 t10 = ff6769c5d964b800 t11= 000000000000b886 pv = ffffffff811bea20 at = 0000000000000000 gp = ffffffff81d89690 sp = 00000000aa814126 Disabling lock debugging due to kernel taint Trace: [] si_dma_is_lockup+0x34/0xd0 [] radeon_fence_check_lockup+0xd0/0x290 [] process_one_work+0x280/0x550 [] worker_thread+0x70/0x7c0 [] worker_thread+0x130/0x7c0 [] kthread+0x200/0x210 [] worker_thread+0x0/0x7c0 [] kthread+0x14c/0x210 [] ret_from_kernel_thread+0x18/0x20 [] kthread+0x0/0x210 Code: ad3e0008 43f0074a ad7e0018 ad9e0020 8c3001e8 40230101 <88210000> 4821ed21 So force lockup work queue flush to fix this problem. Acked-by: Christian König Signed-off-by: Zhenneng Li Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/radeon/radeon_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4f0fbf6674316..92905ebb7b459 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1617,6 +1617,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, if (r) { /* delay GPU reset to resume */ radeon_fence_driver_force_completion(rdev, i); + } else { + /* finish executing delayed work */ + flush_delayed_work(&rdev->fence_drv[i].lockup_work); } } From c501891293747411ecbbf59a0d0b3a0fb82e11a6 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 11 Aug 2022 16:43:49 -0700 Subject: [PATCH 123/228] scsi: ufs: core: Reduce the power mode change timeout [ Upstream commit 8f2c96420c6ec3dcb18c8be923e24c6feaa5ccf6 ] The current power mode change timeout (180 s) is so large that it can cause a watchdog timer to fire. Reduce the power mode change timeout to 10 seconds. Link: https://lore.kernel.org/r/20220811234401.1957911-1-bvanassche@acm.org Reviewed-by: Stanley Chu Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/ufs/ufshcd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2f6468f22b489..dae1a85f1512c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8476,6 +8476,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, struct scsi_device *sdp; unsigned long flags; int ret, retries; + unsigned long deadline; + int32_t remaining; spin_lock_irqsave(hba->host->host_lock, flags); sdp = hba->sdev_ufs_device; @@ -8508,9 +8510,14 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, * callbacks hence set the RQF_PM flag so that it doesn't resume the * already suspended childs. */ + deadline = jiffies + 10 * HZ; for (retries = 3; retries > 0; --retries) { + ret = -ETIMEDOUT; + remaining = deadline - jiffies; + if (remaining <= 0) + break; ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, - START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL); + remaining / HZ, 0, 0, RQF_PM, NULL); if (!scsi_status_is_check_condition(ret) || !scsi_sense_valid(&sshdr) || sshdr.sense_key != UNIT_ATTENTION) From c63ff388e7d434c97109f4ed7f56e79fabd0757c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 21 Aug 2022 08:12:19 +0200 Subject: [PATCH 124/228] Revert "parisc: Show error if wrong 32/64-bit compiler is being used" [ Upstream commit b4b18f47f4f9682fbf5827682645da7c8dde8f80 ] This reverts commit b160628e9ebcdc85d0db9d7f423c26b3c7c179d0. There is no need any longer to have this sanity check, because the previous commit ("parisc: Make CONFIG_64BIT available for ARCH=parisc64 only") prevents that CONFIG_64BIT is set if ARCH==parisc. Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- arch/parisc/include/asm/bitops.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/parisc/include/asm/bitops.h b/arch/parisc/include/asm/bitops.h index 5779d463b341f..aa4e883431c1a 100644 --- a/arch/parisc/include/asm/bitops.h +++ b/arch/parisc/include/asm/bitops.h @@ -12,14 +12,6 @@ #include #include -/* compiler build environment sanity checks: */ -#if !defined(CONFIG_64BIT) && defined(__LP64__) -#error "Please use 'ARCH=parisc' to build the 32-bit kernel." -#endif -#if defined(CONFIG_64BIT) && !defined(__LP64__) -#error "Please use 'ARCH=parisc64' to build the 64-bit kernel." -#endif - /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion * on use of volatile and __*_bit() (set/clear/change): * *_bit() want use of volatile. From deb2c9c0770b0e7e2387341e34ed4e47d6b92eaa Mon Sep 17 00:00:00 2001 From: Li Qiong Date: Fri, 19 Aug 2022 12:15:10 +0800 Subject: [PATCH 125/228] parisc: ccio-dma: Handle kmalloc failure in ccio_init_resources() [ Upstream commit d46c742f827fa2326ab1f4faa1cccadb56912341 ] As the possible failure of the kmalloc(), it should be better to fix this error path, check and return '-ENOMEM' error code. Signed-off-by: Li Qiong Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- drivers/parisc/ccio-dma.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 9be007c9420f9..f69ab90b5e22d 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1380,15 +1380,17 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) } } -static void __init ccio_init_resources(struct ioc *ioc) +static int __init ccio_init_resources(struct ioc *ioc) { struct resource *res = ioc->mmio_region; char *name = kmalloc(14, GFP_KERNEL); - + if (unlikely(!name)) + return -ENOMEM; snprintf(name, 14, "GSC Bus [%d/]", ioc->hw_path); ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low); ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv); + return 0; } static int new_ioc_area(struct resource *res, unsigned long size, @@ -1543,7 +1545,10 @@ static int __init ccio_probe(struct parisc_device *dev) return -ENOMEM; } ccio_ioc_init(ioc); - ccio_init_resources(ioc); + if (ccio_init_resources(ioc)) { + kfree(ioc); + return -ENOMEM; + } hppa_dma_ops = &ccio_ops; hba = kzalloc(sizeof(*hba), GFP_KERNEL); From 27092358e9c6dd0a5c01092496e5e10102841fef Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 21 Aug 2022 14:49:58 +0200 Subject: [PATCH 126/228] parisc: Add runtime check to prevent PA2.0 kernels on PA1.x machines [ Upstream commit 591d2108f3abc4db9f9073cae37cf3591fd250d6 ] If a 32-bit kernel was compiled for PA2.0 CPUs, it won't be able to run on machines with PA1.x CPUs. Add a check and bail out early if a PA1.x machine is detected. Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- arch/parisc/kernel/head.S | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index aa93d775c34db..598d0938449da 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -22,7 +22,7 @@ #include #include - .level PA_ASM_LEVEL + .level 1.1 __INITDATA ENTRY(boot_args) @@ -69,6 +69,47 @@ $bss_loop: stw,ma %arg2,4(%r1) stw,ma %arg3,4(%r1) +#if !defined(CONFIG_64BIT) && defined(CONFIG_PA20) + /* This 32-bit kernel was compiled for PA2.0 CPUs. Check current CPU + * and halt kernel if we detect a PA1.x CPU. */ + ldi 32,%r10 + mtctl %r10,%cr11 + .level 2.0 + mfctl,w %cr11,%r10 + .level 1.1 + comib,<>,n 0,%r10,$cpu_ok + + load32 PA(msg1),%arg0 + ldi msg1_end-msg1,%arg1 +$iodc_panic: + copy %arg0, %r10 + copy %arg1, %r11 + load32 PA(init_stack),%sp +#define MEM_CONS 0x3A0 + ldw MEM_CONS+32(%r0),%arg0 // HPA + ldi ENTRY_IO_COUT,%arg1 + ldw MEM_CONS+36(%r0),%arg2 // SPA + ldw MEM_CONS+8(%r0),%arg3 // layers + load32 PA(__bss_start),%r1 + stw %r1,-52(%sp) // arg4 + stw %r0,-56(%sp) // arg5 + stw %r10,-60(%sp) // arg6 = ptr to text + stw %r11,-64(%sp) // arg7 = len + stw %r0,-68(%sp) // arg8 + load32 PA(.iodc_panic_ret), %rp + ldw MEM_CONS+40(%r0),%r1 // ENTRY_IODC + bv,n (%r1) +.iodc_panic_ret: + b . /* wait endless with ... */ + or %r10,%r10,%r10 /* qemu idle sleep */ +msg1: .ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n" +msg1_end: + +$cpu_ok: +#endif + + .level PA_ASM_LEVEL + /* Initialize startup VM. Just map first 16/32 MB of memory */ load32 PA(swapper_pg_dir),%r4 mtctl %r4,%cr24 /* Initialize kernel root pointer */ From 29906311b351e5398aff2c5dc209f8b6c9d6a410 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 8 Aug 2022 09:46:40 +0100 Subject: [PATCH 127/228] arm64: cacheinfo: Fix incorrect assignment of signed error value to unsigned fw_level [ Upstream commit e75d18cecbb3805895d8ed64da4f78575ec96043 ] Though acpi_find_last_cache_level() always returned signed value and the document states it will return any errors caused by lack of a PPTT table, it never returned negative values before. Commit 0c80f9e165f8 ("ACPI: PPTT: Leave the table mapped for the runtime usage") however changed it by returning -ENOENT if no PPTT was found. The value returned from acpi_find_last_cache_level() is then assigned to unsigned fw_level. It will result in the number of cache leaves calculated incorrectly as a huge value which will then cause the following warning from __alloc_pages as the order would be great than MAX_ORDER because of incorrect and huge cache leaves value. | WARNING: CPU: 0 PID: 1 at mm/page_alloc.c:5407 __alloc_pages+0x74/0x314 | Modules linked in: | CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.19.0-10393-g7c2a8d3ac4c0 #73 | pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) | pc : __alloc_pages+0x74/0x314 | lr : alloc_pages+0xe8/0x318 | Call trace: | __alloc_pages+0x74/0x314 | alloc_pages+0xe8/0x318 | kmalloc_order_trace+0x68/0x1dc | __kmalloc+0x240/0x338 | detect_cache_attributes+0xe0/0x56c | update_siblings_masks+0x38/0x284 | store_cpu_topology+0x78/0x84 | smp_prepare_cpus+0x48/0x134 | kernel_init_freeable+0xc4/0x14c | kernel_init+0x2c/0x1b4 | ret_from_fork+0x10/0x20 Fix the same by changing fw_level to be signed integer and return the error from init_cache_level() early in case of error. Reported-and-Tested-by: Bruno Goncalves Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20220808084640.3165368-1-sudeep.holla@arm.com Signed-off-by: Will Deacon Signed-off-by: Sasha Levin --- arch/arm64/kernel/cacheinfo.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c index 587543c6c51cb..97c42be71338a 100644 --- a/arch/arm64/kernel/cacheinfo.c +++ b/arch/arm64/kernel/cacheinfo.c @@ -45,7 +45,8 @@ static void ci_leaf_init(struct cacheinfo *this_leaf, int init_cache_level(unsigned int cpu) { - unsigned int ctype, level, leaves, fw_level; + unsigned int ctype, level, leaves; + int fw_level; struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { @@ -63,6 +64,9 @@ int init_cache_level(unsigned int cpu) else fw_level = acpi_find_last_cache_level(cpu); + if (fw_level < 0) + return fw_level; + if (level < fw_level) { /* * some external caches not specified in CLIDR_EL1 From e928cf258910b15cf626abe20722a72d637c8de3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 19 Aug 2022 00:42:31 +0200 Subject: [PATCH 128/228] netfilter: conntrack: work around exceeded receive window [ Upstream commit cf97769c761abfeac8931b35fe0e1a8d5fabc9d8 ] When a TCP sends more bytes than allowed by the receive window, all future packets can be marked as invalid. This can clog up the conntrack table because of 5-day default timeout. Sequence of packets: 01 initiator > responder: [S], seq 171, win 5840, options [mss 1330,sackOK,TS val 63 ecr 0,nop,wscale 1] 02 responder > initiator: [S.], seq 33211, ack 172, win 65535, options [mss 1460,sackOK,TS val 010 ecr 63,nop,wscale 8] 03 initiator > responder: [.], ack 33212, win 2920, options [nop,nop,TS val 068 ecr 010], length 0 04 initiator > responder: [P.], seq 172:240, ack 33212, win 2920, options [nop,nop,TS val 279 ecr 010], length 68 Window is 5840 starting from 33212 -> 39052. 05 responder > initiator: [.], ack 240, win 256, options [nop,nop,TS val 872 ecr 279], length 0 06 responder > initiator: [.], seq 33212:34530, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 1318 This is fine, conntrack will flag the connection as having outstanding data (UNACKED), which lowers the conntrack timeout to 300s. 07 responder > initiator: [.], seq 34530:35848, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 1318 08 responder > initiator: [.], seq 35848:37166, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 1318 09 responder > initiator: [.], seq 37166:38484, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 1318 10 responder > initiator: [.], seq 38484:39802, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 1318 Packet 10 is already sending more than permitted, but conntrack doesn't validate this (only seq is tested vs. maxend, not 'seq+len'). 38484 is acceptable, but only up to 39052, so this packet should not have been sent (or only 568 bytes, not 1318). At this point, connection is still in '300s' mode. Next packet however will get flagged: 11 responder > initiator: [P.], seq 39802:40128, ack 240, win 256, options [nop,nop,TS val 892 ecr 279], length 326 nf_ct_proto_6: SEQ is over the upper bound (over the window of the receiver) .. LEN=378 .. SEQ=39802 ACK=240 ACK PSH .. Now, a couple of replies/acks comes in: 12 initiator > responder: [.], ack 34530, win 4368, [.. irrelevant acks removed ] 16 initiator > responder: [.], ack 39802, win 8712, options [nop,nop,TS val 296201291 ecr 2982371892], length 0 This ack is significant -- this acks the last packet send by the responder that conntrack considered valid. This means that ack == td_end. This will withdraw the 'unacked data' flag, the connection moves back to the 5-day timeout of established conntracks. 17 initiator > responder: ack 40128, win 10030, ... This packet is also flagged as invalid. Because conntrack only updates state based on packets that are considered valid, packet 11 'did not exist' and that gets us: nf_ct_proto_6: ACK is over upper bound 39803 (ACKed data not seen yet) .. SEQ=240 ACK=40128 WINDOW=10030 RES=0x00 ACK URG Because this received and processed by the endpoints, the conntrack entry remains in a bad state, no packets will ever be considered valid again: 30 responder > initiator: [F.], seq 40432, ack 2045, win 391, .. 31 initiator > responder: [.], ack 40433, win 11348, .. 32 initiator > responder: [F.], seq 2045, ack 40433, win 11348 .. ... all trigger 'ACK is over bound' test and we end up with non-early-evictable 5-day default timeout. NB: This patch triggers a bunch of checkpatch warnings because of silly indent. I will resend the cleanup series linked below to reduce the indent level once this change has propagated to net-next. I could route the cleanup via nf but that causes extra backport work for stable maintainers. Link: https://lore.kernel.org/netfilter-devel/20220720175228.17880-1-fw@strlen.de/T/#mb1d7147d36294573cc4f81d00f9f8dadfdd06cd8 Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_proto_tcp.c | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 3cee5d8ee7027..1ecfdc4f23be8 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -671,6 +671,37 @@ static bool tcp_in_window(struct nf_conn *ct, tn->tcp_be_liberal) res = true; if (!res) { + bool seq_ok = before(seq, sender->td_maxend + 1); + + if (!seq_ok) { + u32 overshot = end - sender->td_maxend + 1; + bool ack_ok; + + ack_ok = after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1); + + if (in_recv_win && + ack_ok && + overshot <= receiver->td_maxwin && + before(sack, receiver->td_end + 1)) { + /* Work around TCPs that send more bytes than allowed by + * the receive window. + * + * If the (marked as invalid) packet is allowed to pass by + * the ruleset and the peer acks this data, then its possible + * all future packets will trigger 'ACK is over upper bound' check. + * + * Thus if only the sequence check fails then do update td_end so + * possible ACK for this data can update internal state. + */ + sender->td_end = end; + sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; + + nf_ct_l4proto_log_invalid(skb, ct, hook_state, + "%u bytes more than expected", overshot); + return res; + } + } + nf_ct_l4proto_log_invalid(skb, ct, hook_state, "%s", before(seq, sender->td_maxend + 1) ? From bd1b769564eb0eae61bdf0dbb9b569b089cf36ac Mon Sep 17 00:00:00 2001 From: Lukasz Luba Date: Tue, 16 Aug 2022 13:01:57 +0100 Subject: [PATCH 129/228] cpufreq: check only freq_table in __resolve_freq() [ Upstream commit 6ca7076fbfaeccce173aeab832d76b9e49e1034b ] There is no need to check if the cpufreq driver implements callback cpufreq_driver::target_index. The logic in the __resolve_freq uses the frequency table available in the policy. It doesn't matter if the driver provides 'target_index' or 'target' callback. It just has to populate the 'policy->freq_table'. Thus, check only frequency table during the frequency resolving call. Acked-by: Viresh Kumar Signed-off-by: Lukasz Luba Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index cddf7e13c2322..799431d287ee8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -532,7 +532,7 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy, target_freq = clamp_val(target_freq, policy->min, policy->max); - if (!cpufreq_driver->target_index) + if (!policy->freq_table) return target_freq; idx = cpufreq_frequency_table_target(policy, target_freq, relation); From 0b7058067eb8ec143f415a42d6909a28f166de5f Mon Sep 17 00:00:00 2001 From: lily Date: Mon, 22 Aug 2022 22:44:11 -0700 Subject: [PATCH 130/228] net/core/skbuff: Check the return value of skb_copy_bits() [ Upstream commit c624c58e08b15105662b9ab9be23d14a6b945a49 ] skb_copy_bits() could fail, which requires a check on the return value. Signed-off-by: Li Zhong Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/core/skbuff.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 563848242ad33..3c193e7d4bc67 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4188,9 +4188,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, SKB_GSO_CB(nskb)->csum_start = skb_headroom(nskb) + doffset; } else { - skb_copy_bits(head_skb, offset, - skb_put(nskb, len), - len); + if (skb_copy_bits(head_skb, offset, skb_put(nskb, len), len)) + goto err; } continue; } From a7dff6f41e16959b27021d522575c915a0de9916 Mon Sep 17 00:00:00 2001 From: David Sloan Date: Thu, 11 Aug 2022 11:14:13 -0600 Subject: [PATCH 131/228] md: Flush workqueue md_rdev_misc_wq in md_alloc() [ Upstream commit 5e8daf906f890560df430d30617c692a794acb73 ] A race condition still exists when removing and re-creating md devices in test cases. However, it is only seen on some setups. The race condition was tracked down to a reference still being held to the kobject by the rdev in the md_rdev_misc_wq which will be released in rdev_delayed_delete(). md_alloc() waits for previous deletions by waiting on the md_misc_wq, but the md_rdev_misc_wq may still be holding a reference to a recently removed device. To fix this, also flush the md_rdev_misc_wq in md_alloc(). Signed-off-by: David Sloan [logang@deltatee.com: rewrote commit message] Signed-off-by: Logan Gunthorpe Signed-off-by: Song Liu Signed-off-by: Sasha Levin --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index c8f2e8524bfb7..04e1e294b4b1e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5651,6 +5651,7 @@ static int md_alloc(dev_t dev, char *name) * removed (mddev_delayed_delete). */ flush_workqueue(md_misc_wq); + flush_workqueue(md_rdev_misc_wq); mutex_lock(&disks_mutex); mddev = mddev_alloc(dev); From c3abfd6ce2f3833151a4501e80a48f824b3b5f4d Mon Sep 17 00:00:00 2001 From: Shigeru Yoshida Date: Sun, 21 Aug 2022 20:17:31 +0900 Subject: [PATCH 132/228] fbdev: fbcon: Destroy mutex on freeing struct fb_info [ Upstream commit 58559dfc1ebba2ae0c7627dc8f8991ae1984c6e3 ] It's needed to destroy bl_curve_mutex on freeing struct fb_info since the mutex is embedded in the structure and initialized when it's allocated. Signed-off-by: Shigeru Yoshida Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- drivers/video/fbdev/core/fbsysfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index ce699396d6bad..09ee27e7fc25f 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -84,6 +84,10 @@ void framebuffer_release(struct fb_info *info) if (WARN_ON(refcount_read(&info->count))) return; +#if IS_ENABLED(CONFIG_FB_BACKLIGHT) + mutex_destroy(&info->bl_curve_mutex); +#endif + kfree(info->apertures); kfree(info); } From fc5a2a9616f38d4c3fe49d196ea5827ced80a3a7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 19 Aug 2022 16:57:52 +0800 Subject: [PATCH 133/228] fbdev: chipsfb: Add missing pci_disable_device() in chipsfb_pci_init() [ Upstream commit 07c55c9803dea748d17a054000cbf1913ce06399 ] Add missing pci_disable_device() in error path in chipsfb_pci_init(). Signed-off-by: Yang Yingliang Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- drivers/video/fbdev/chipsfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index 393894af26f84..2b00a9d554fc0 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -430,6 +430,7 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) err_release_fb: framebuffer_release(p); err_disable: + pci_disable_device(dp); err_out: return rc; } From ad5ef763dbbea8193bd2095a1401aeac6e8f74e8 Mon Sep 17 00:00:00 2001 From: Qu Huang Date: Tue, 23 Aug 2022 14:44:06 +0800 Subject: [PATCH 134/228] drm/amdgpu: mmVM_L2_CNTL3 register not initialized correctly [ Upstream commit b8983d42524f10ac6bf35bbce6a7cc8e45f61e04 ] The mmVM_L2_CNTL3 register is not assigned an initial value Signed-off-by: Qu Huang Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index b3bede1dc41da..4259f623a9d7a 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -176,6 +176,7 @@ static void mmhub_v1_0_init_cache_regs(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1); WREG32_SOC15(MMHUB, 0, mmVM_L2_CNTL2, tmp); + tmp = mmVM_L2_CNTL3_DEFAULT; if (adev->gmc.translate_further) { tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, BANK_SELECT, 12); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, From 8015ef9e8a0ee5cecfd0cb6805834d007ab26f86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Sep 2022 08:07:14 +0200 Subject: [PATCH 135/228] ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC commit 8423f0b6d513b259fdab9c9bf4aaa6188d054c2d upstream. There is a small race window at snd_pcm_oss_sync() that is called from OSS PCM SNDCTL_DSP_SYNC ioctl; namely the function calls snd_pcm_oss_make_ready() at first, then takes the params_lock mutex for the rest. When the stream is set up again by another thread between them, it leads to inconsistency, and may result in unexpected results such as NULL dereference of OSS buffer as a fuzzer spotted recently. The fix is simply to cover snd_pcm_oss_make_ready() call into the same params_lock mutex with snd_pcm_oss_make_ready_locked() variant. Reported-and-tested-by: butt3rflyh4ck Reviewed-by: Jaroslav Kysela Cc: Link: https://lore.kernel.org/r/CAFcO6XN7JDM4xSXGhtusQfS2mSBcx50VJKwQpCq=WeLt57aaZA@mail.gmail.com Link: https://lore.kernel.org/r/20220905060714.22549-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f158f0abd25d8..ca4a692fe1c36 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1664,14 +1664,14 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) goto __direct; - err = snd_pcm_oss_make_ready(substream); - if (err < 0) - return err; atomic_inc(&runtime->oss.rw_ref); if (mutex_lock_interruptible(&runtime->oss.params_lock)) { atomic_dec(&runtime->oss.rw_ref); return -ERESTARTSYS; } + err = snd_pcm_oss_make_ready_locked(substream); + if (err < 0) + goto unlock; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); if (runtime->oss.buffer_used > 0) { From 45814a53514e10a8014906c882e0d0d38df39cc1 Mon Sep 17 00:00:00 2001 From: Tasos Sahanidis Date: Wed, 7 Sep 2022 04:18:00 +0300 Subject: [PATCH 136/228] ALSA: emu10k1: Fix out of bounds access in snd_emu10k1_pcm_channel_alloc() commit d29f59051d3a07b81281b2df2b8c9dfe4716067f upstream. The voice allocator sometimes begins allocating from near the end of the array and then wraps around, however snd_emu10k1_pcm_channel_alloc() accesses the newly allocated voices as if it never wrapped around. This results in out of bounds access if the first voice has a high enough index so that first_voice + requested_voice_count > NUM_G (64). The more voices are requested, the more likely it is for this to occur. This was initially discovered using PipeWire, however it can be reproduced by calling aplay multiple times with 16 channels: aplay -r 48000 -D plughw:CARD=Live,DEV=3 -c 16 /dev/zero UBSAN: array-index-out-of-bounds in sound/pci/emu10k1/emupcm.c:127:40 index 65 is out of range for type 'snd_emu10k1_voice [64]' CPU: 1 PID: 31977 Comm: aplay Tainted: G W IOE 6.0.0-rc2-emu10k1+ #7 Hardware name: ASUSTEK COMPUTER INC P5W DH Deluxe/P5W DH Deluxe, BIOS 3002 07/22/2010 Call Trace: dump_stack_lvl+0x49/0x63 dump_stack+0x10/0x16 ubsan_epilogue+0x9/0x3f __ubsan_handle_out_of_bounds.cold+0x44/0x49 snd_emu10k1_playback_hw_params+0x3bc/0x420 [snd_emu10k1] snd_pcm_hw_params+0x29f/0x600 [snd_pcm] snd_pcm_common_ioctl+0x188/0x1410 [snd_pcm] ? exit_to_user_mode_prepare+0x35/0x170 ? do_syscall_64+0x69/0x90 ? syscall_exit_to_user_mode+0x26/0x50 ? do_syscall_64+0x69/0x90 ? exit_to_user_mode_prepare+0x35/0x170 snd_pcm_ioctl+0x27/0x40 [snd_pcm] __x64_sys_ioctl+0x95/0xd0 do_syscall_64+0x5c/0x90 ? do_syscall_64+0x69/0x90 ? do_syscall_64+0x69/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd Signed-off-by: Tasos Sahanidis Cc: Link: https://lore.kernel.org/r/3707dcab-320a-62ff-63c0-73fc201ef756@tasossah.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/emupcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index b2701a4452d86..48af77ae8020f 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -124,7 +124,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic epcm->voices[0]->epcm = epcm; if (voices > 1) { for (i = 1; i < voices; i++) { - epcm->voices[i] = &epcm->emu->voices[epcm->voices[0]->number + i]; + epcm->voices[i] = &epcm->emu->voices[(epcm->voices[0]->number + i) % NUM_G]; epcm->voices[i]->epcm = epcm; } } From d1118465ae2eb9a7ae7be894f73d99585f889df9 Mon Sep 17 00:00:00 2001 From: Pattara Teerapong Date: Thu, 1 Sep 2022 14:40:36 +0000 Subject: [PATCH 137/228] ALSA: aloop: Fix random zeros in capture data when using jiffies timer commit 3e48940abee88b8dbbeeaf8a07e7b2b6be1271b3 upstream. In loopback_jiffies_timer_pos_update(), we are getting jiffies twice. First time for playback, second time for capture. Jiffies can be updated between these two calls and if the capture jiffies is larger, extra zeros will be filled in the capture buffer. Change to get jiffies once and use it for both playback and capture. Signed-off-by: Pattara Teerapong Cc: Link: https://lore.kernel.org/r/20220901144036.4049060-1-pteerapong@chromium.org Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 9b4a7cdb103ad..12f12a294df5a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -605,17 +605,18 @@ static unsigned int loopback_jiffies_timer_pos_update cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; struct loopback_pcm *dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; - unsigned long delta_play = 0, delta_capt = 0; + unsigned long delta_play = 0, delta_capt = 0, cur_jiffies; unsigned int running, count1, count2; + cur_jiffies = jiffies; running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { - delta_play = jiffies - dpcm_play->last_jiffies; + delta_play = cur_jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; } if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { - delta_capt = jiffies - dpcm_capt->last_jiffies; + delta_capt = cur_jiffies - dpcm_capt->last_jiffies; dpcm_capt->last_jiffies += delta_capt; } From df5ec554e9e35110971381e7c658ef945ace9905 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Sep 2022 14:41:36 +0200 Subject: [PATCH 138/228] ALSA: usb-audio: Split endpoint setups for hw_params and prepare commit ff878b408a03bef5d610b7e2302702e16a53636e upstream. One of the former changes for the endpoint management was the more consistent setup of endpoints at hw_params. snd_usb_endpoint_configure() is a single function that does the full setup, and it's called from both PCM hw_params and prepare callbacks. Although the EP setup at the prepare phase is usually skipped (by checking need_setup flag), it may be still effective in some cases like suspend/resume that requires the interface setup again. As it's a full and single setup, the invocation of snd_usb_endpoint_configure() includes not only the USB interface setup but also the buffer release and allocation. OTOH, doing the buffer release and re-allocation at PCM prepare phase is rather superfluous, and better to be done only in the hw_params phase. For those optimizations, this patch splits the endpoint setup to two phases: snd_usb_endpoint_set_params() and snd_usb_endpoint_prepare(), to be called from hw_params and from prepare, respectively. Note that this patch changes the driver operation slightly, effectively moving the USB interface setup again to PCM prepare stage instead of hw_params stage, while the buffer allocation and such initializations are still done at hw_params stage. And, the change of the USB interface setup timing (moving to prepare) gave an interesting "fix", too: it was reported that the recent kernels caused silent output at the beginning on playbacks on some devices on Android, and this change casually fixed the regression. It seems that those devices are picky about the sample rate change (or the interface change?), and don't follow the too immediate rate changes. Meanwhile, Android operates the PCM in the following order: - open, then hw_params with the possibly highest sample rate - close without prepare - re-open, hw_params with the normal sample rate - prepare, and start streaming This procedure ended up the hw_params twice with different rates, and because the recent kernel did set up the sample rate twice one and after, it screwed up the device. OTOH, the earlier kernels didn't set up the USB interface at hw_params, hence this problem didn't appear. Now, with this patch, the USB interface setup is again back to the prepare phase, and it works around the problem automagically. Although we should address the sample rate problem in a more solid way in future, let's keep things working as before for now. Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management") Cc: Reported-by: chihhao chen Link: https://lore.kernel.org/r/87e6d6ae69d68dc588ac9acc8c0f24d6188375c3.camel@mediatek.com Link: https://lore.kernel.org/r/20220901124136.4984-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/endpoint.c | 23 +++++++++-------------- sound/usb/endpoint.h | 6 ++++-- sound/usb/pcm.c | 14 ++++++++++---- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 743b8287cfcdd..11fa7745c017e 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -731,7 +731,8 @@ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, * The endpoint needs to be closed via snd_usb_endpoint_close() later. * * Note that this function doesn't configure the endpoint. The substream - * needs to set it up later via snd_usb_endpoint_configure(). + * needs to set it up later via snd_usb_endpoint_set_params() and + * snd_usb_endpoint_prepare(). */ struct snd_usb_endpoint * snd_usb_endpoint_open(struct snd_usb_audio *chip, @@ -1254,12 +1255,13 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep) /* * snd_usb_endpoint_set_params: configure an snd_usb_endpoint * + * It's called either from hw_params callback. * Determine the number of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ -static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { const struct audioformat *fmt = ep->cur_audiofmt; int err; @@ -1315,18 +1317,18 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, } /* - * snd_usb_endpoint_configure: Configure the endpoint + * snd_usb_endpoint_prepare: Prepare the endpoint * * This function sets up the EP to be fully usable state. - * It's called either from hw_params or prepare callback. + * It's called either from prepare callback. * The function checks need_setup flag, and performs nothing unless needed, * so it's safe to call this multiple times. * * This returns zero if unchanged, 1 if the configuration has changed, * or a negative error code. */ -int snd_usb_endpoint_configure(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { bool iface_first; int err = 0; @@ -1348,9 +1350,6 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip, if (err < 0) goto unlock; } - err = snd_usb_endpoint_set_params(chip, ep); - if (err < 0) - goto unlock; goto done; } @@ -1378,10 +1377,6 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip, if (err < 0) goto unlock; - err = snd_usb_endpoint_set_params(chip, ep); - if (err < 0) - goto unlock; - err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); if (err < 0) goto unlock; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 6a9af04cf175a..e67ea28faa54f 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -17,8 +17,10 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, bool is_sync_ep); void snd_usb_endpoint_close(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep); -int snd_usb_endpoint_configure(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep); +int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); +int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock); bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index b6cd43c5ea3e6..2d60e6d1f8dff 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -443,17 +443,17 @@ static int configure_endpoints(struct snd_usb_audio *chip, if (stop_endpoints(subs, false)) sync_pending_stops(subs); if (subs->sync_endpoint) { - err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); + err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (err < 0) return err; } - err = snd_usb_endpoint_configure(chip, subs->data_endpoint); + err = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (err < 0) return err; snd_usb_set_format_quirk(subs, subs->cur_audiofmt); } else { if (subs->sync_endpoint) { - err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); + err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (err < 0) return err; } @@ -551,7 +551,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->cur_audiofmt = fmt; mutex_unlock(&chip->mutex); - ret = configure_endpoints(chip, subs); + if (subs->sync_endpoint) { + ret = snd_usb_endpoint_set_params(chip, subs->sync_endpoint); + if (ret < 0) + goto unlock; + } + + ret = snd_usb_endpoint_set_params(chip, subs->data_endpoint); unlock: if (ret < 0) From 98e8e67395cc6d0cdf3a771f86ea42d0ee6e59dd Mon Sep 17 00:00:00 2001 From: Dongxiang Ke Date: Tue, 6 Sep 2022 10:49:28 +0800 Subject: [PATCH 139/228] ALSA: usb-audio: Fix an out-of-bounds bug in __snd_usb_parse_audio_interface() commit e53f47f6c1a56d2af728909f1cb894da6b43d9bf upstream. There may be a bad USB audio device with a USB ID of (0x04fa, 0x4201) and the number of it's interfaces less than 4, an out-of-bounds read bug occurs when parsing the interface descriptor for this device. Fix this by checking the number of interfaces. Signed-off-by: Dongxiang Ke Link: https://lore.kernel.org/r/20220906024928.10951-1-kdx.glider@gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index ceb93d798182c..40ce8a1cb318a 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1105,7 +1105,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, * Dallas DS4201 workaround: It presents 5 altsettings, but the last * one misses syncpipe, and does not produce any sound. */ - if (chip->usb_id == USB_ID(0x04fa, 0x4201)) + if (chip->usb_id == USB_ID(0x04fa, 0x4201) && num >= 4) num = 4; for (i = 0; i < num; i++) { From 75082adeb414113ce1afa710c50f8dacdd8245b0 Mon Sep 17 00:00:00 2001 From: "Masami Hiramatsu (Google)" Date: Sun, 4 Sep 2022 13:12:29 +0900 Subject: [PATCH 140/228] tracing: Fix to check event_mutex is held while accessing trigger list commit cecf8e128ec69149fe53c9a7bafa505a4bee25d9 upstream. Since the check_user_trigger() is called outside of RCU read lock, this list_for_each_entry_rcu() caused a suspicious RCU usage warning. # echo hist:keys=pid > events/sched/sched_stat_runtime/trigger # cat events/sched/sched_stat_runtime/trigger [ 43.167032] [ 43.167418] ============================= [ 43.167992] WARNING: suspicious RCU usage [ 43.168567] 5.19.0-rc5-00029-g19ebe4651abf #59 Not tainted [ 43.169283] ----------------------------- [ 43.169863] kernel/trace/trace_events_trigger.c:145 RCU-list traversed in non-reader section!! ... However, this file->triggers list is safe when it is accessed under event_mutex is held. To fix this warning, adds a lockdep_is_held check to the list_for_each_entry_rcu(). Link: https://lkml.kernel.org/r/166226474977.223837.1992182913048377113.stgit@devnote2 Cc: stable@vger.kernel.org Fixes: 7491e2c44278 ("tracing: Add a probe that attaches to trace events") Signed-off-by: Masami Hiramatsu (Google) Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 67c7979c40c0b..106f9813841a1 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -128,7 +128,8 @@ static bool check_user_trigger(struct trace_event_file *file) { struct event_trigger_data *data; - list_for_each_entry_rcu(data, &file->triggers, list) { + list_for_each_entry_rcu(data, &file->triggers, list, + lockdep_is_held(&event_mutex)) { if (data->flags & EVENT_TRIGGER_FL_PROBE) continue; return true; From 7da1afa444a19dec5ac49c2f8eae1838562a18f1 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Fri, 26 Aug 2022 16:42:15 +0900 Subject: [PATCH 141/228] btrfs: zoned: set pseudo max append zone limit in zone emulation mode commit cac5c44c48c9fb9cc31bea15ebd9ef0c6462314f upstream. The commit 7d7672bc5d10 ("btrfs: convert count_max_extents() to use fs_info->max_extent_size") introduced a division by fs_info->max_extent_size. This max_extent_size is initialized with max zone append limit size of the device btrfs runs on. However, in zone emulation mode, the device is not zoned then its zone append limit is zero. This resulted in zero value of fs_info->max_extent_size and caused zero division error. Fix the error by setting non-zero pseudo value to max append zone limit in zone emulation mode. Set the pseudo value based on max_segments as suggested in the commit c2ae7b772ef4 ("btrfs: zoned: revive max_zone_append_bytes"). Fixes: 7d7672bc5d10 ("btrfs: convert count_max_extents() to use fs_info->max_extent_size") CC: stable@vger.kernel.org # 5.12+ Reviewed-by: Johannes Thumshirn Reviewed-by: Naohiro Aota Signed-off-by: Shin'ichiro Kawasaki Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/zoned.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 7a127d3c521f9..96958ca474bd4 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -392,10 +392,19 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache) * since btrfs adds the pages one by one to a bio, and btrfs cannot * increase the metadata reservation even if it increases the number of * extents, it is safe to stick with the limit. + * + * With the zoned emulation, we can have non-zoned device on the zoned + * mode. In this case, we don't have a valid max zone append size. So, + * use max_segments * PAGE_SIZE as the pseudo max_zone_append_size. */ - zone_info->max_zone_append_size = - min_t(u64, (u64)bdev_max_zone_append_sectors(bdev) << SECTOR_SHIFT, - (u64)bdev_max_segments(bdev) << PAGE_SHIFT); + if (bdev_is_zoned(bdev)) { + zone_info->max_zone_append_size = min_t(u64, + (u64)bdev_max_zone_append_sectors(bdev) << SECTOR_SHIFT, + (u64)bdev_max_segments(bdev) << PAGE_SHIFT); + } else { + zone_info->max_zone_append_size = + (u64)bdev_max_segments(bdev) << PAGE_SHIFT; + } if (!IS_ALIGNED(nr_sectors, zone_sectors)) zone_info->nr_zones++; From 5321908ef74fb593e0dbc8737d25038fc86c9986 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 29 Aug 2022 21:05:40 -0600 Subject: [PATCH 142/228] vfio/type1: Unpin zero pages commit 873aefb376bbc0ed1dd2381ea1d6ec88106fdbd4 upstream. There's currently a reference count leak on the zero page. We increment the reference via pin_user_pages_remote(), but the page is later handled as an invalid/reserved page, therefore it's not accounted against the user and not unpinned by our put_pfn(). Introducing special zero page handling in put_pfn() would resolve the leak, but without accounting of the zero page, a single user could still create enough mappings to generate a reference count overflow. The zero page is always resident, so for our purposes there's no reason to keep it pinned. Therefore, add a loop to walk pages returned from pin_user_pages_remote() and unpin any zero pages. Cc: stable@vger.kernel.org Reported-by: Luboslav Pivarc Reviewed-by: David Hildenbrand Link: https://lore.kernel.org/r/166182871735.3518559.8884121293045337358.stgit@omen Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/vfio_iommu_type1.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 0e9217687f5c3..852e6c5643e5d 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -561,6 +561,18 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, ret = pin_user_pages_remote(mm, vaddr, npages, flags | FOLL_LONGTERM, pages, NULL, NULL); if (ret > 0) { + int i; + + /* + * The zero page is always resident, we don't need to pin it + * and it falls into our invalid/reserved test so we don't + * unpin in put_pfn(). Unpin all zero pages in the batch here. + */ + for (i = 0 ; i < ret; i++) { + if (unlikely(is_zero_pfn(page_to_pfn(pages[i])))) + unpin_user_page(pages[i]); + } + *pfn = page_to_pfn(pages[0]); goto done; } From 8875d606761e721d283e3fbb650a69f850b7d216 Mon Sep 17 00:00:00 2001 From: "Christian A. Ehrhardt" Date: Wed, 7 Sep 2022 22:09:17 +0200 Subject: [PATCH 143/228] kprobes: Prohibit probes in gate area commit 1efda38d6f9ba26ac88b359c6277f1172db03f1e upstream. The system call gate area counts as kernel text but trying to install a kprobe in this area fails with an Oops later on. To fix this explicitly disallow the gate area for kprobes. Found by syzkaller with the following reproducer: perf_event_open$cgroup(&(0x7f00000001c0)={0x6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x80ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @perf_config_ext={0x0, 0xffffffffff600000}}, 0xffffffffffffffff, 0x0, 0xffffffffffffffff, 0x0) Sample report: BUG: unable to handle page fault for address: fffffbfff3ac6000 PGD 6dfcb067 P4D 6dfcb067 PUD 6df8f067 PMD 6de4d067 PTE 0 Oops: 0000 [#1] PREEMPT SMP KASAN NOPTI CPU: 0 PID: 21978 Comm: syz-executor.2 Not tainted 6.0.0-rc3-00363-g7726d4c3e60b-dirty #6 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:__insn_get_emulate_prefix arch/x86/lib/insn.c:91 [inline] RIP: 0010:insn_get_emulate_prefix arch/x86/lib/insn.c:106 [inline] RIP: 0010:insn_get_prefixes.part.0+0xa8/0x1110 arch/x86/lib/insn.c:134 Code: 49 be 00 00 00 00 00 fc ff df 48 8b 40 60 48 89 44 24 08 e9 81 00 00 00 e8 e5 4b 39 ff 4c 89 fa 4c 89 f9 48 c1 ea 03 83 e1 07 <42> 0f b6 14 32 38 ca 7f 08 84 d2 0f 85 06 10 00 00 48 89 d8 48 89 RSP: 0018:ffffc900088bf860 EFLAGS: 00010246 RAX: 0000000000040000 RBX: ffffffff9b9bebc0 RCX: 0000000000000000 RDX: 1ffffffff3ac6000 RSI: ffffc90002d82000 RDI: ffffc900088bf9e8 RBP: ffffffff9d630001 R08: 0000000000000000 R09: ffffc900088bf9e8 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000001 R13: ffffffff9d630000 R14: dffffc0000000000 R15: ffffffff9d630000 FS: 00007f63eef63640(0000) GS:ffff88806d000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: fffffbfff3ac6000 CR3: 0000000029d90005 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: insn_get_prefixes arch/x86/lib/insn.c:131 [inline] insn_get_opcode arch/x86/lib/insn.c:272 [inline] insn_get_modrm+0x64a/0x7b0 arch/x86/lib/insn.c:343 insn_get_sib+0x29a/0x330 arch/x86/lib/insn.c:421 insn_get_displacement+0x350/0x6b0 arch/x86/lib/insn.c:464 insn_get_immediate arch/x86/lib/insn.c:632 [inline] insn_get_length arch/x86/lib/insn.c:707 [inline] insn_decode+0x43a/0x490 arch/x86/lib/insn.c:747 can_probe+0xfc/0x1d0 arch/x86/kernel/kprobes/core.c:282 arch_prepare_kprobe+0x79/0x1c0 arch/x86/kernel/kprobes/core.c:739 prepare_kprobe kernel/kprobes.c:1160 [inline] register_kprobe kernel/kprobes.c:1641 [inline] register_kprobe+0xb6e/0x1690 kernel/kprobes.c:1603 __register_trace_kprobe kernel/trace/trace_kprobe.c:509 [inline] __register_trace_kprobe+0x26a/0x2d0 kernel/trace/trace_kprobe.c:477 create_local_trace_kprobe+0x1f7/0x350 kernel/trace/trace_kprobe.c:1833 perf_kprobe_init+0x18c/0x280 kernel/trace/trace_event_perf.c:271 perf_kprobe_event_init+0xf8/0x1c0 kernel/events/core.c:9888 perf_try_init_event+0x12d/0x570 kernel/events/core.c:11261 perf_init_event kernel/events/core.c:11325 [inline] perf_event_alloc.part.0+0xf7f/0x36a0 kernel/events/core.c:11619 perf_event_alloc kernel/events/core.c:12059 [inline] __do_sys_perf_event_open+0x4a8/0x2a00 kernel/events/core.c:12157 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f63ef7efaed Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 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 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f63eef63028 EFLAGS: 00000246 ORIG_RAX: 000000000000012a RAX: ffffffffffffffda RBX: 00007f63ef90ff80 RCX: 00007f63ef7efaed RDX: 0000000000000000 RSI: ffffffffffffffff RDI: 00000000200001c0 RBP: 00007f63ef86019c R08: 0000000000000000 R09: 0000000000000000 R10: ffffffffffffffff R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000002 R14: 00007f63ef90ff80 R15: 00007f63eef43000 Modules linked in: CR2: fffffbfff3ac6000 ---[ end trace 0000000000000000 ]--- RIP: 0010:__insn_get_emulate_prefix arch/x86/lib/insn.c:91 [inline] RIP: 0010:insn_get_emulate_prefix arch/x86/lib/insn.c:106 [inline] RIP: 0010:insn_get_prefixes.part.0+0xa8/0x1110 arch/x86/lib/insn.c:134 Code: 49 be 00 00 00 00 00 fc ff df 48 8b 40 60 48 89 44 24 08 e9 81 00 00 00 e8 e5 4b 39 ff 4c 89 fa 4c 89 f9 48 c1 ea 03 83 e1 07 <42> 0f b6 14 32 38 ca 7f 08 84 d2 0f 85 06 10 00 00 48 89 d8 48 89 RSP: 0018:ffffc900088bf860 EFLAGS: 00010246 RAX: 0000000000040000 RBX: ffffffff9b9bebc0 RCX: 0000000000000000 RDX: 1ffffffff3ac6000 RSI: ffffc90002d82000 RDI: ffffc900088bf9e8 RBP: ffffffff9d630001 R08: 0000000000000000 R09: ffffc900088bf9e8 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000001 R13: ffffffff9d630000 R14: dffffc0000000000 R15: ffffffff9d630000 FS: 00007f63eef63640(0000) GS:ffff88806d000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: fffffbfff3ac6000 CR3: 0000000029d90005 CR4: 0000000000770ef0 PKRU: 55555554 ================================================================== Link: https://lkml.kernel.org/r/20220907200917.654103-1-lk@c--e.de cc: "Naveen N. Rao" cc: Anil S Keshavamurthy cc: "David S. Miller" Cc: stable@vger.kernel.org Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Acked-by: Masami Hiramatsu (Google) Signed-off-by: Christian A. Ehrhardt Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/kprobes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index ed3f24a81549c..9df585b9467e4 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1561,6 +1561,7 @@ static int check_kprobe_address_safe(struct kprobe *p, /* Ensure it is not in reserved area nor out of text */ if (!(core_kernel_text((unsigned long) p->addr) || is_module_text_address((unsigned long) p->addr)) || + in_gate_area_no_mm((unsigned long) p->addr) || within_kprobe_blacklist((unsigned long) p->addr) || jump_label_text_reserved(p->addr, p->addr) || static_call_text_reserved(p->addr, p->addr) || From 94c84128adb190a7621505891566145de206224a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Sep 2022 16:59:15 +0200 Subject: [PATCH 144/228] debugfs: add debugfs_lookup_and_remove() commit dec9b2f1e0455a151a7293c367da22ab973f713e upstream. There is a very common pattern of using debugfs_remove(debufs_lookup(..)) which results in a dentry leak of the dentry that was looked up. Instead of having to open-code the correct pattern of calling dput() on the dentry, create debugfs_lookup_and_remove() to handle this pattern automatically and properly without any memory leaks. Cc: stable Reported-by: Kuyo Chang Tested-by: Kuyo Chang Link: https://lore.kernel.org/r/YxIaQ8cSinDR881k@kroah.com Signed-off-by: Greg Kroah-Hartman --- fs/debugfs/inode.c | 22 ++++++++++++++++++++++ include/linux/debugfs.h | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 2f117c57160dc..26f9cd3282918 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -734,6 +734,28 @@ void debugfs_remove(struct dentry *dentry) } EXPORT_SYMBOL_GPL(debugfs_remove); +/** + * debugfs_lookup_and_remove - lookup a directory or file and recursively remove it + * @name: a pointer to a string containing the name of the item to look up. + * @parent: a pointer to the parent dentry of the item. + * + * This is the equlivant of doing something like + * debugfs_remove(debugfs_lookup(..)) but with the proper reference counting + * handled for the directory being looked up. + */ +void debugfs_lookup_and_remove(const char *name, struct dentry *parent) +{ + struct dentry *dentry; + + dentry = debugfs_lookup(name, parent); + if (!dentry) + return; + + debugfs_remove(dentry); + dput(dentry); +} +EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove); + /** * debugfs_rename - rename a file/directory in the debugfs filesystem * @old_dir: a pointer to the parent dentry for the renamed object. This diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index c869f1e73d755..f60674692d365 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -91,6 +91,8 @@ struct dentry *debugfs_create_automount(const char *name, void debugfs_remove(struct dentry *dentry); #define debugfs_remove_recursive debugfs_remove +void debugfs_lookup_and_remove(const char *name, struct dentry *parent); + const struct file_operations *debugfs_real_fops(const struct file *filp); int debugfs_file_get(struct dentry *dentry); @@ -225,6 +227,10 @@ static inline void debugfs_remove(struct dentry *dentry) static inline void debugfs_remove_recursive(struct dentry *dentry) { } +static inline void debugfs_lookup_and_remove(const char *name, + struct dentry *parent) +{ } + const struct file_operations *debugfs_real_fops(const struct file *filp); static inline int debugfs_file_get(struct dentry *dentry) From 26e9a1ded8923510e5529fbb28390b22228700c2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Sep 2022 14:31:07 +0200 Subject: [PATCH 145/228] sched/debug: fix dentry leak in update_sched_domain_debugfs commit c2e406596571659451f4b95e37ddfd5a8ef1d0dc upstream. Kuyo reports that the pattern of using debugfs_remove(debugfs_lookup()) leaks a dentry and with a hotplug stress test, the machine eventually runs out of memory. Fix this up by using the newly created debugfs_lookup_and_remove() call instead which properly handles the dentry reference counting logic. Cc: Major Chen Cc: stable Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Juri Lelli Cc: Vincent Guittot Cc: Dietmar Eggemann Cc: Steven Rostedt Cc: Ben Segall Cc: Mel Gorman Cc: Daniel Bristot de Oliveira Cc: Valentin Schneider Cc: Matthias Brugger Reported-by: Kuyo Chang Tested-by: Kuyo Chang Acked-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20220902123107.109274-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- kernel/sched/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 7a2d32d2025fe..34c5ff3a0669b 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -416,7 +416,7 @@ void update_sched_domain_debugfs(void) char buf[32]; snprintf(buf, sizeof(buf), "cpu%d", cpu); - debugfs_remove(debugfs_lookup(buf, sd_dentry)); + debugfs_lookup_and_remove(buf, sd_dentry); d_cpu = debugfs_create_dir(buf, sd_dentry); i = 0; From 58acd2ebae034db3bacf38708f508fbd12ae2e54 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Sep 2022 15:01:05 +0200 Subject: [PATCH 146/228] drm/amd/display: fix memory leak when using debugfs_lookup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cbfac7fa491651c57926c99edeb7495c6c1aeac2 upstream. When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. Fix this up by properly calling dput(). Cc: Harry Wentland Cc: Leo Li Cc: Rodrigo Siqueira Cc: Alex Deucher Cc: "Christian König" Cc: "Pan, Xinhui" Cc: David Airlie Cc: Daniel Vetter Cc: Wayne Lin Cc: hersen wu Cc: Wenjing Liu Cc: Patrik Jakobsson Cc: Thelford Williams Cc: Fangzhi Zuo Cc: Yongzhi Liu Cc: Mikita Lipski Cc: Jiapeng Chong Cc: Bhanuprakash Modem Cc: Sean Paul Cc: amd-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Cc: stable@vger.kernel.org Reviewed-by: Rodrigo Siqueira Signed-off-by: Greg Kroah-Hartman Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 5c9f5214bc4e9..6d694cea24201 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -3007,7 +3007,7 @@ void crtc_debugfs_init(struct drm_crtc *crtc) &crc_win_y_end_fops); debugfs_create_file_unsafe("crc_win_update", 0644, dir, crtc, &crc_win_update_fops); - + dput(dir); } #endif /* From ebf46da50beb78066674354ad650606a467e33fa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 12 Aug 2022 14:03:17 -0700 Subject: [PATCH 147/228] nvmet: fix a use-after-free commit 6a02a61e81c231cc5c680c5dbf8665275147ac52 upstream. Fix the following use-after-free complaint triggered by blktests nvme/004: BUG: KASAN: user-memory-access in blk_mq_complete_request_remote+0xac/0x350 Read of size 4 at addr 0000607bd1835943 by task kworker/13:1/460 Workqueue: nvmet-wq nvme_loop_execute_work [nvme_loop] Call Trace: show_stack+0x52/0x58 dump_stack_lvl+0x49/0x5e print_report.cold+0x36/0x1e2 kasan_report+0xb9/0xf0 __asan_load4+0x6b/0x80 blk_mq_complete_request_remote+0xac/0x350 nvme_loop_queue_response+0x1df/0x275 [nvme_loop] __nvmet_req_complete+0x132/0x4f0 [nvmet] nvmet_req_complete+0x15/0x40 [nvmet] nvmet_execute_io_connect+0x18a/0x1f0 [nvmet] nvme_loop_execute_work+0x20/0x30 [nvme_loop] process_one_work+0x56e/0xa70 worker_thread+0x2d1/0x640 kthread+0x183/0x1c0 ret_from_fork+0x1f/0x30 Cc: stable@vger.kernel.org Fixes: a07b4970f464 ("nvmet: add a generic NVMe target") Signed-off-by: Bart Van Assche Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index a8dafe8670f20..0a0c1d956c73a 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -736,6 +736,8 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status) static void __nvmet_req_complete(struct nvmet_req *req, u16 status) { + struct nvmet_ns *ns = req->ns; + if (!req->sq->sqhd_disabled) nvmet_update_sq_head(req); req->cqe->sq_id = cpu_to_le16(req->sq->qid); @@ -746,9 +748,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status) trace_nvmet_req_complete(req); - if (req->ns) - nvmet_put_namespace(req->ns); req->ops->queue_response(req); + if (ns) + nvmet_put_namespace(ns); } void nvmet_req_complete(struct nvmet_req *req, u16 status) From d2ca79dd0b5487991dac52c6b679915dbd70ee4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 2 Sep 2022 10:03:18 +0300 Subject: [PATCH 148/228] drm/i915: Implement WaEdpLinkRateDataReload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 672d6ca758651f0ec12cd0d59787067a5bde1c96 upstream. A lot of modern laptops use the Parade PS8461E MUX for eDP switching. The MUX can operate in jitter cleaning mode or redriver mode, the first one resulting in higher link quality. The jitter cleaning mode needs to know the link rate used and the MUX achieves this by snooping the LINK_BW_SET, LINK_RATE_SELECT and SUPPORTED_LINK_RATES DPCD accesses. When the MUX is powered down (seems this can happen whenever the display is turned off) it loses track of the snooped link rates so when we do the LINK_RATE_SELECT write it no longer knowns which link rate we're selecting, and thus it falls back to the lower quality redriver mode. This results in unstable high link rates (eg. usually 8.1Gbps link rate no longer works correctly). In order to avoid all that let's re-snoop SUPPORTED_LINK_RATES from the sink at the start of every link training. Unfortunately we don't have a way to detect the presence of the MUX. It looks like the set of laptops equipped with this MUX is fairly large and contains devices from multiple manufacturers. It may also still be growing with new models. So a quirk doesn't seem like a very easily maintainable option, thus we shall attempt to do this unconditionally on all machines that use LINK_RATE_SELECT. Hopefully this extra DPCD read doesn't cause issues for any unaffected machine. If that turns out to be the case we'll need to convert this into a quirk in the future. Cc: stable@vger.kernel.org Cc: Jason A. Donenfeld Cc: Ankit Nautiyal Cc: Jani Nikula Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6205 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220902070319.15395-1-ville.syrjala@linux.intel.com Tested-by: Aaron Ma Tested-by: Jason A. Donenfeld Reviewed-by: Jani Nikula (cherry picked from commit 25899c590cb5ba9b9f284c6ca8e7e9086793d641) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- .../drm/i915/display/intel_dp_link_training.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 508a514c5e37d..d77d91c0a03af 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -475,6 +475,28 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp, intel_dp_compute_rate(intel_dp, crtc_state->port_clock, &link_bw, &rate_select); + /* + * WaEdpLinkRateDataReload + * + * Parade PS8461E MUX (used on varius TGL+ laptops) needs + * to snoop the link rates reported by the sink when we + * use LINK_RATE_SET in order to operate in jitter cleaning + * mode (as opposed to redriver mode). Unfortunately it + * loses track of the snooped link rates when powered down, + * so we need to make it re-snoop often. Without this high + * link rates are not stable. + */ + if (!link_bw) { + struct intel_connector *connector = intel_dp->attached_connector; + __le16 sink_rates[DP_MAX_SUPPORTED_RATES]; + + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Reloading eDP link rates\n", + connector->base.base.id, connector->base.name); + + drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES, + sink_rates, sizeof(sink_rates)); + } + if (link_bw) drm_dbg_kms(&i915->drm, "Using LINK_BW_SET value %02x\n", link_bw); From 6229fa494a5949be209bc73afbc5d0a749c2e3c7 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 6 Sep 2022 19:19:08 +0530 Subject: [PATCH 149/228] scsi: mpt3sas: Fix use-after-free warning commit 991df3dd5144f2e6b1c38b8d20ed3d4d21e20b34 upstream. Fix the following use-after-free warning which is observed during controller reset: refcount_t: underflow; use-after-free. WARNING: CPU: 23 PID: 5399 at lib/refcount.c:28 refcount_warn_saturate+0xa6/0xf0 Link: https://lore.kernel.org/r/20220906134908.1039-2-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5351959fbaba3..9eb3d0b4891dd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -3670,6 +3670,7 @@ static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) fw_event = list_first_entry(&ioc->fw_event_list, struct fw_event_work, list); list_del_init(&fw_event->list); + fw_event_work_put(fw_event); } spin_unlock_irqrestore(&ioc->fw_event_lock, flags); @@ -3751,7 +3752,6 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) if (cancel_work_sync(&fw_event->work)) fw_event_work_put(fw_event); - fw_event_work_put(fw_event); } ioc->fw_events_cleanup = 0; } From 1dcc308898e7b0b6b3cf688f45a4b3e556e8a78a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 23 Aug 2022 12:42:37 +0800 Subject: [PATCH 150/228] scsi: lpfc: Add missing destroy_workqueue() in error path commit da6d507f5ff328f346b3c50e19e19993027b8ffd upstream. Add the missing destroy_workqueue() before return from lpfc_sli4_driver_resource_setup() in the error path. Link: https://lore.kernel.org/r/20220823044237.285643-1-yangyingliang@huawei.com Fixes: 3cee98db2610 ("scsi: lpfc: Fix crash on driver unload in wq free") Reviewed-by: James Smart Signed-off-by: Yang Yingliang Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6d04b3323eb7e..33e33fff89865 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7893,7 +7893,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate device driver memory */ rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ); if (rc) - return -ENOMEM; + goto out_destroy_workqueue; /* IF Type 2 ports get initialized now. */ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= @@ -8309,6 +8309,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) lpfc_destroy_bootstrap_mbox(phba); out_free_mem: lpfc_mem_free(phba); +out_destroy_workqueue: + destroy_workqueue(phba->wq); + phba->wq = NULL; return rc; } From 88d24e83a268007564f9222b177c1381b9e794cd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 14:33:44 -0400 Subject: [PATCH 151/228] NFS: Further optimisations for 'ls -l' [ Upstream commit ff81dfb5d721fff87bd516c558847f6effb70031 ] If a user is doing 'ls -l', we have a heuristic in GETATTR that tells the readdir code to try to use READDIRPLUS in order to refresh the inode attributes. In certain cirumstances, we also try to invalidate the remaining directory entries in order to ensure this refresh. If there are multiple readers of the directory, we probably should avoid invalidating the page cache, since the heuristic breaks down in that situation anyway. Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington Signed-off-by: Sasha Levin --- fs/nfs/dir.c | 16 +++++++++++----- include/linux/nfs_fs.h | 5 ++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 78219396788b4..32c3d0c454b19 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -78,6 +78,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir ctx->attr_gencount = nfsi->attr_gencount; ctx->dir_cookie = 0; ctx->dup_cookie = 0; + ctx->page_index = 0; spin_lock(&dir->i_lock); if (list_empty(&nfsi->open_files) && (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) @@ -85,6 +86,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir NFS_INO_INVALID_DATA | NFS_INO_REVAL_FORCED); list_add(&ctx->list, &nfsi->open_files); + clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags); spin_unlock(&dir->i_lock); return ctx; } @@ -626,8 +628,7 @@ void nfs_force_use_readdirplus(struct inode *dir) if (nfs_server_capable(dir, NFS_CAP_READDIRPLUS) && !list_empty(&nfsi->open_files)) { set_bit(NFS_INO_ADVISE_RDPLUS, &nfsi->flags); - invalidate_mapping_pages(dir->i_mapping, - nfsi->page_index + 1, -1); + set_bit(NFS_INO_FORCE_READDIR, &nfsi->flags); } } @@ -938,10 +939,8 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc) sizeof(nfsi->cookieverf)); } res = nfs_readdir_search_array(desc); - if (res == 0) { - nfsi->page_index = desc->page_index; + if (res == 0) return 0; - } nfs_readdir_page_unlock_and_put_cached(desc); return res; } @@ -1081,6 +1080,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_dir_context *dir_ctx = file->private_data; struct nfs_readdir_descriptor *desc; + pgoff_t page_index; int res; dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n", @@ -1111,10 +1111,15 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) desc->dir_cookie = dir_ctx->dir_cookie; desc->dup_cookie = dir_ctx->dup_cookie; desc->duped = dir_ctx->duped; + page_index = dir_ctx->page_index; desc->attr_gencount = dir_ctx->attr_gencount; memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf)); spin_unlock(&file->f_lock); + if (test_and_clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags) && + list_is_singular(&nfsi->open_files)) + invalidate_mapping_pages(inode->i_mapping, page_index + 1, -1); + do { res = readdir_search_pagecache(desc); @@ -1151,6 +1156,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) dir_ctx->dup_cookie = desc->dup_cookie; dir_ctx->duped = desc->duped; dir_ctx->attr_gencount = desc->attr_gencount; + dir_ctx->page_index = desc->page_index; memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf)); spin_unlock(&file->f_lock); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 66b6cc24ab8c9..be8625d8a10a7 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -103,6 +103,7 @@ struct nfs_open_dir_context { __be32 verf[NFS_DIR_VERIFIER_SIZE]; __u64 dir_cookie; __u64 dup_cookie; + pgoff_t page_index; signed char duped; }; @@ -181,9 +182,6 @@ struct nfs_inode { struct rw_semaphore rmdir_sem; struct mutex commit_mutex; - /* track last access to cached pages */ - unsigned long page_index; - #if IS_ENABLED(CONFIG_NFS_V4) struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */ @@ -272,6 +270,7 @@ struct nfs4_copy_state { #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ +#define NFS_INO_FORCE_READDIR (7) /* force readdirplus */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ From 31b992b3c39b2e1a3cfd86085ecf2b8a8730b210 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 17:41:41 -0400 Subject: [PATCH 152/228] NFS: Save some space in the inode [ Upstream commit e591b298d7ecb851e200f65946e3d53fe78a3c4f ] Save some space in the nfs_inode by setting up an anonymous union with the fields that are peculiar to a specific type of filesystem object. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/inode.c | 26 ++++++++++++++++++-------- include/linux/nfs_fs.h | 42 ++++++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index cb407af9e9e92..dc057ab6b30d1 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -431,6 +431,22 @@ nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh) return inode; } +static void nfs_inode_init_regular(struct nfs_inode *nfsi) +{ + atomic_long_set(&nfsi->nrequests, 0); + INIT_LIST_HEAD(&nfsi->commit_info.list); + atomic_long_set(&nfsi->commit_info.ncommit, 0); + atomic_set(&nfsi->commit_info.rpcs_out, 0); + mutex_init(&nfsi->commit_mutex); +} + +static void nfs_inode_init_dir(struct nfs_inode *nfsi) +{ + nfsi->cache_change_attribute = 0; + memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); + init_rwsem(&nfsi->rmdir_sem); +} + /* * This is our front-end to iget that looks up inodes by file handle * instead of inode number. @@ -485,10 +501,12 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st if (S_ISREG(inode->i_mode)) { inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops; inode->i_data.a_ops = &nfs_file_aops; + nfs_inode_init_regular(nfsi); } else if (S_ISDIR(inode->i_mode)) { inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; inode->i_fop = &nfs_dir_operations; inode->i_data.a_ops = &nfs_dir_aops; + nfs_inode_init_dir(nfsi); /* Deal with crossing mountpoints */ if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT || fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { @@ -514,7 +532,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st inode->i_uid = make_kuid(&init_user_ns, -2); inode->i_gid = make_kgid(&init_user_ns, -2); inode->i_blocks = 0; - memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); nfsi->write_io = 0; nfsi->read_io = 0; @@ -2282,14 +2299,7 @@ static void init_once(void *foo) INIT_LIST_HEAD(&nfsi->open_files); INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); - INIT_LIST_HEAD(&nfsi->commit_info.list); - atomic_long_set(&nfsi->nrequests, 0); - atomic_long_set(&nfsi->commit_info.ncommit, 0); - atomic_set(&nfsi->commit_info.rpcs_out, 0); - init_rwsem(&nfsi->rmdir_sem); - mutex_init(&nfsi->commit_mutex); nfs4_init_once(nfsi); - nfsi->cache_change_attribute = 0; } static int __init nfs_init_inodecache(void) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index be8625d8a10a7..d0855352cd6fc 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -155,33 +155,39 @@ struct nfs_inode { unsigned long attrtimeo_timestamp; unsigned long attr_gencount; - /* "Generation counter" for the attribute cache. This is - * bumped whenever we update the metadata on the - * server. - */ - unsigned long cache_change_attribute; struct rb_root access_cache; struct list_head access_cache_entry_lru; struct list_head access_cache_inode_lru; - /* - * This is the cookie verifier used for NFSv3 readdir - * operations - */ - __be32 cookieverf[NFS_DIR_VERIFIER_SIZE]; - - atomic_long_t nrequests; - struct nfs_mds_commit_info commit_info; + union { + /* Directory */ + struct { + /* "Generation counter" for the attribute cache. + * This is bumped whenever we update the metadata + * on the server. + */ + unsigned long cache_change_attribute; + /* + * This is the cookie verifier used for NFSv3 readdir + * operations + */ + __be32 cookieverf[NFS_DIR_VERIFIER_SIZE]; + /* Readers: in-flight sillydelete RPC calls */ + /* Writers: rmdir */ + struct rw_semaphore rmdir_sem; + }; + /* Regular file */ + struct { + atomic_long_t nrequests; + struct nfs_mds_commit_info commit_info; + struct mutex commit_mutex; + }; + }; /* Open contexts for shared mmap writes */ struct list_head open_files; - /* Readers: in-flight sillydelete RPC calls */ - /* Writers: rmdir */ - struct rw_semaphore rmdir_sem; - struct mutex commit_mutex; - #if IS_ENABLED(CONFIG_NFS_V4) struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */ From 3b97deb4abf5aa39785d9915ce3cf0531436c91b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 13 Aug 2022 08:22:25 -0400 Subject: [PATCH 153/228] NFS: Fix another fsync() issue after a server reboot [ Upstream commit 67f4b5dc49913abcdb5cc736e73674e2f352f81d ] Currently, when the writeback code detects a server reboot, it redirties any pages that were not committed to disk, and it sets the flag NFS_CONTEXT_RESEND_WRITES in the nfs_open_context of the file descriptor that dirtied the file. While this allows the file descriptor in question to redrive its own writes, it violates the fsync() requirement that we should be synchronising all writes to disk. While the problem is infrequent, we do see corner cases where an untimely server reboot causes the fsync() call to abandon its attempt to sync data to disk and causing data corruption issues due to missed error conditions or similar. In order to tighted up the client's ability to deal with this situation without introducing livelocks, add a counter that records the number of times pages are redirtied due to a server reboot-like condition, and use that in fsync() to redrive the sync to disk. Fixes: 2197e9b06c22 ("NFS: Fix up fsync() when the server rebooted") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/file.c | 15 ++++++--------- fs/nfs/inode.c | 1 + fs/nfs/write.c | 6 ++++-- include/linux/nfs_fs.h | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index a8693cc50c7ca..ad5114e480097 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -223,8 +223,10 @@ nfs_file_fsync_commit(struct file *file, int datasync) int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) { - struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = file_inode(file); + struct nfs_inode *nfsi = NFS_I(inode); + long save_nredirtied = atomic_long_read(&nfsi->redirtied_pages); + long nredirtied; int ret; trace_nfs_fsync_enter(inode); @@ -239,15 +241,10 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) ret = pnfs_sync_inode(inode, !!datasync); if (ret != 0) break; - if (!test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags)) + nredirtied = atomic_long_read(&nfsi->redirtied_pages); + if (nredirtied == save_nredirtied) break; - /* - * If nfs_file_fsync_commit detected a server reboot, then - * resend all dirty pages that might have been covered by - * the NFS_CONTEXT_RESEND_WRITES flag - */ - start = 0; - end = LLONG_MAX; + save_nredirtied = nredirtied; } trace_nfs_fsync_exit(inode, ret); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index dc057ab6b30d1..e4524635a129a 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -434,6 +434,7 @@ nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh) static void nfs_inode_init_regular(struct nfs_inode *nfsi) { atomic_long_set(&nfsi->nrequests, 0); + atomic_long_set(&nfsi->redirtied_pages, 0); INIT_LIST_HEAD(&nfsi->commit_info.list); atomic_long_set(&nfsi->commit_info.ncommit, 0); atomic_set(&nfsi->commit_info.rpcs_out, 0); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index cdb29fd235492..be70874bc3292 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1394,10 +1394,12 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr, */ static void nfs_redirty_request(struct nfs_page *req) { + struct nfs_inode *nfsi = NFS_I(page_file_mapping(req->wb_page)->host); + /* Bump the transmission count */ req->wb_nio++; nfs_mark_request_dirty(req); - set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags); + atomic_long_inc(&nfsi->redirtied_pages); nfs_end_page_writeback(req); nfs_release_request(req); } @@ -1870,7 +1872,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) /* We have a mismatch. Write the page again */ dprintk_cont(" mismatch\n"); nfs_mark_request_dirty(req); - set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags); + atomic_long_inc(&NFS_I(data->inode)->redirtied_pages); next: nfs_unlock_and_release_request(req); /* Latency breaker */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index d0855352cd6fc..71467d661fb66 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -180,6 +180,7 @@ struct nfs_inode { /* Regular file */ struct { atomic_long_t nrequests; + atomic_long_t redirtied_pages; struct nfs_mds_commit_info commit_info; struct mutex commit_mutex; }; From 509e3456d3635fe8a7fc87ed772fcfe20b6ea0bc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 14 Jul 2022 18:38:15 -1000 Subject: [PATCH 154/228] cgroup: Elide write-locking threadgroup_rwsem when updating csses on an empty subtree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 671c11f0619e5ccb380bcf0f062f69ba95fc974a ] cgroup_update_dfl_csses() write-lock the threadgroup_rwsem as updating the csses can trigger process migrations. However, if the subtree doesn't contain any tasks, there aren't gonna be any cgroup migrations. This condition can be trivially detected by testing whether mgctx.preloaded_src_csets is empty. Elide write-locking threadgroup_rwsem if the subtree is empty. After this optimization, the usage pattern of creating a cgroup, enabling the necessary controllers, and then seeding it with CLONE_INTO_CGROUP and then removing the cgroup after it becomes empty doesn't need to write-lock threadgroup_rwsem at all. Signed-off-by: Tejun Heo Cc: Christian Brauner Cc: Michal Koutný Signed-off-by: Sasha Levin --- kernel/cgroup/cgroup.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 416dd7db3fb2c..baebd1c7667b7 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2949,12 +2949,11 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) struct cgroup_subsys_state *d_css; struct cgroup *dsct; struct css_set *src_cset; + bool has_tasks; int ret; lockdep_assert_held(&cgroup_mutex); - percpu_down_write(&cgroup_threadgroup_rwsem); - /* look up all csses currently attached to @cgrp's subtree */ spin_lock_irq(&css_set_lock); cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) { @@ -2965,6 +2964,16 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) } spin_unlock_irq(&css_set_lock); + /* + * We need to write-lock threadgroup_rwsem while migrating tasks. + * However, if there are no source csets for @cgrp, changing its + * controllers isn't gonna produce any task migrations and the + * write-locking can be skipped safely. + */ + has_tasks = !list_empty(&mgctx.preloaded_src_csets); + if (has_tasks) + percpu_down_write(&cgroup_threadgroup_rwsem); + /* NULL dst indicates self on default hierarchy */ ret = cgroup_migrate_prepare_dst(&mgctx); if (ret) @@ -2984,7 +2993,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) ret = cgroup_migrate_execute(&mgctx); out_finish: cgroup_migrate_finish(&mgctx); - percpu_up_write(&cgroup_threadgroup_rwsem); + if (has_tasks) + percpu_up_write(&cgroup_threadgroup_rwsem); return ret; } From 3bf4bf54069f9b62a54988e5d085023c17a66c90 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 Aug 2022 13:27:38 -1000 Subject: [PATCH 155/228] cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock [ Upstream commit 4f7e7236435ca0abe005c674ebd6892c6e83aeb3 ] Bringing up a CPU may involve creating and destroying tasks which requires read-locking threadgroup_rwsem, so threadgroup_rwsem nests inside cpus_read_lock(). However, cpuset's ->attach(), which may be called with thredagroup_rwsem write-locked, also wants to disable CPU hotplug and acquires cpus_read_lock(), leading to a deadlock. Fix it by guaranteeing that ->attach() is always called with CPU hotplug disabled and removing cpus_read_lock() call from cpuset_attach(). Signed-off-by: Tejun Heo Reviewed-and-tested-by: Imran Khan Reported-and-tested-by: Xuewen Yan Fixes: 05c7b7a92cc8 ("cgroup/cpuset: Fix a race between cpuset_attach() and cpu hotplug") Cc: stable@vger.kernel.org # v5.17+ Signed-off-by: Sasha Levin --- kernel/cgroup/cgroup.c | 77 +++++++++++++++++++++++++++++------------- kernel/cgroup/cpuset.c | 3 +- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index baebd1c7667b7..75c3881af0784 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2345,6 +2345,47 @@ int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) } EXPORT_SYMBOL_GPL(task_cgroup_path); +/** + * cgroup_attach_lock - Lock for ->attach() + * @lock_threadgroup: whether to down_write cgroup_threadgroup_rwsem + * + * cgroup migration sometimes needs to stabilize threadgroups against forks and + * exits by write-locking cgroup_threadgroup_rwsem. However, some ->attach() + * implementations (e.g. cpuset), also need to disable CPU hotplug. + * Unfortunately, letting ->attach() operations acquire cpus_read_lock() can + * lead to deadlocks. + * + * Bringing up a CPU may involve creating and destroying tasks which requires + * read-locking threadgroup_rwsem, so threadgroup_rwsem nests inside + * cpus_read_lock(). If we call an ->attach() which acquires the cpus lock while + * write-locking threadgroup_rwsem, the locking order is reversed and we end up + * waiting for an on-going CPU hotplug operation which in turn is waiting for + * the threadgroup_rwsem to be released to create new tasks. For more details: + * + * http://lkml.kernel.org/r/20220711174629.uehfmqegcwn2lqzu@wubuntu + * + * Resolve the situation by always acquiring cpus_read_lock() before optionally + * write-locking cgroup_threadgroup_rwsem. This allows ->attach() to assume that + * CPU hotplug is disabled on entry. + */ +static void cgroup_attach_lock(bool lock_threadgroup) +{ + cpus_read_lock(); + if (lock_threadgroup) + percpu_down_write(&cgroup_threadgroup_rwsem); +} + +/** + * cgroup_attach_unlock - Undo cgroup_attach_lock() + * @lock_threadgroup: whether to up_write cgroup_threadgroup_rwsem + */ +static void cgroup_attach_unlock(bool lock_threadgroup) +{ + if (lock_threadgroup) + percpu_up_write(&cgroup_threadgroup_rwsem); + cpus_read_unlock(); +} + /** * cgroup_migrate_add_task - add a migration target task to a migration context * @task: target task @@ -2821,8 +2862,7 @@ int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader, } struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup, - bool *locked) - __acquires(&cgroup_threadgroup_rwsem) + bool *threadgroup_locked) { struct task_struct *tsk; pid_t pid; @@ -2839,12 +2879,8 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup, * Therefore, we can skip the global lock. */ lockdep_assert_held(&cgroup_mutex); - if (pid || threadgroup) { - percpu_down_write(&cgroup_threadgroup_rwsem); - *locked = true; - } else { - *locked = false; - } + *threadgroup_locked = pid || threadgroup; + cgroup_attach_lock(*threadgroup_locked); rcu_read_lock(); if (pid) { @@ -2875,17 +2911,14 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup, goto out_unlock_rcu; out_unlock_threadgroup: - if (*locked) { - percpu_up_write(&cgroup_threadgroup_rwsem); - *locked = false; - } + cgroup_attach_unlock(*threadgroup_locked); + *threadgroup_locked = false; out_unlock_rcu: rcu_read_unlock(); return tsk; } -void cgroup_procs_write_finish(struct task_struct *task, bool locked) - __releases(&cgroup_threadgroup_rwsem) +void cgroup_procs_write_finish(struct task_struct *task, bool threadgroup_locked) { struct cgroup_subsys *ss; int ssid; @@ -2893,8 +2926,8 @@ void cgroup_procs_write_finish(struct task_struct *task, bool locked) /* release reference from cgroup_procs_write_start() */ put_task_struct(task); - if (locked) - percpu_up_write(&cgroup_threadgroup_rwsem); + cgroup_attach_unlock(threadgroup_locked); + for_each_subsys(ss, ssid) if (ss->post_attach) ss->post_attach(); @@ -2971,8 +3004,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) * write-locking can be skipped safely. */ has_tasks = !list_empty(&mgctx.preloaded_src_csets); - if (has_tasks) - percpu_down_write(&cgroup_threadgroup_rwsem); + cgroup_attach_lock(has_tasks); /* NULL dst indicates self on default hierarchy */ ret = cgroup_migrate_prepare_dst(&mgctx); @@ -2993,8 +3025,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) ret = cgroup_migrate_execute(&mgctx); out_finish: cgroup_migrate_finish(&mgctx); - if (has_tasks) - percpu_up_write(&cgroup_threadgroup_rwsem); + cgroup_attach_unlock(has_tasks); return ret; } @@ -4942,13 +4973,13 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf, struct task_struct *task; const struct cred *saved_cred; ssize_t ret; - bool locked; + bool threadgroup_locked; dst_cgrp = cgroup_kn_lock_live(of->kn, false); if (!dst_cgrp) return -ENODEV; - task = cgroup_procs_write_start(buf, threadgroup, &locked); + task = cgroup_procs_write_start(buf, threadgroup, &threadgroup_locked); ret = PTR_ERR_OR_ZERO(task); if (ret) goto out_unlock; @@ -4974,7 +5005,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf, ret = cgroup_attach_task(dst_cgrp, task, threadgroup); out_finish: - cgroup_procs_write_finish(task, locked); + cgroup_procs_write_finish(task, threadgroup_locked); out_unlock: cgroup_kn_unlock(of->kn); diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 9c5b659db63f4..3213d3c8ea0a8 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2249,7 +2249,7 @@ static void cpuset_attach(struct cgroup_taskset *tset) cgroup_taskset_first(tset, &css); cs = css_cs(css); - cpus_read_lock(); + lockdep_assert_cpus_held(); /* see cgroup_attach_lock() */ percpu_down_write(&cpuset_rwsem); guarantee_online_mems(cs, &cpuset_attach_nodemask_to); @@ -2303,7 +2303,6 @@ static void cpuset_attach(struct cgroup_taskset *tset) wake_up(&cpuset_attach_wq); percpu_up_write(&cpuset_rwsem); - cpus_read_unlock(); } /* The various types of files and directories in a cpuset file system */ From 237f16395304b5ab416e2d0b4d945e0dd6973c6a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 16 Aug 2022 17:52:29 +0100 Subject: [PATCH 156/228] ASoC: qcom: sm8250: add missing module owner [ Upstream commit c6e14bb9f50df7126ca64405ae807d8bc7b39f9a ] Add missing module owner to able to build and load this driver as module. Fixes: aa2e2785545a ("ASoC: qcom: sm8250: add sound card qrb5165-rb5 support") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220816165229.7971-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/qcom/sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index fe8fd7367e21b..e5190aa588c63 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -191,6 +191,7 @@ static int sm8250_platform_probe(struct platform_device *pdev) if (!card) return -ENOMEM; + card->owner = THIS_MODULE; /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) From ad69caa4786181f1b2078b832a964c4eaefbea13 Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Thu, 18 Aug 2022 12:53:54 +0200 Subject: [PATCH 157/228] RDMA/rtrs-clt: Use the right sg_cnt after ib_dma_map_sg [ Upstream commit b66905e04dc714825aa6cffb950e281b46bbeafe ] When iommu is enabled, we hit warnings like this: WARNING: at rtrs/rtrs.c:178 rtrs_iu_post_rdma_write_imm+0x9b/0x110 rtrs warn on one sge entry length is 0, which is unexpected. The problem is ib_dma_map_sg augments the SGL into a 'dma mapped SGL'. This process may change the number of entries and the lengths of each entry. Code that touches dma_address is iterating over the 'dma mapped SGL' and must use dma_nents which returned from ib_dma_map_sg(). So pass the count return from ib_dma_map_sg. Fixes: 6a98d71daea1 ("RDMA/rtrs: client: main functionality") Link: https://lore.kernel.org/r/20220818105355.110344-3-haris.iqbal@ionos.com Signed-off-by: Jack Wang Reviewed-by: Aleksei Marov Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 9edbb309b96c0..c644617725a88 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1011,7 +1011,8 @@ rtrs_clt_get_copy_req(struct rtrs_clt_path *alive_path, static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con, struct rtrs_clt_io_req *req, struct rtrs_rbuf *rbuf, bool fr_en, - u32 size, u32 imm, struct ib_send_wr *wr, + u32 count, u32 size, u32 imm, + struct ib_send_wr *wr, struct ib_send_wr *tail) { struct rtrs_clt_path *clt_path = to_clt_path(con->c.path); @@ -1031,12 +1032,12 @@ static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con, num_sge = 2; ptail = tail; } else { - for_each_sg(req->sglist, sg, req->sg_cnt, i) { + for_each_sg(req->sglist, sg, count, i) { sge[i].addr = sg_dma_address(sg); sge[i].length = sg_dma_len(sg); sge[i].lkey = clt_path->s.dev->ib_pd->local_dma_lkey; } - num_sge = 1 + req->sg_cnt; + num_sge = 1 + count; } sge[i].addr = req->iu->dma_addr; sge[i].length = size; @@ -1149,7 +1150,7 @@ static int rtrs_clt_write_req(struct rtrs_clt_io_req *req) */ rtrs_clt_update_all_stats(req, WRITE); - ret = rtrs_post_rdma_write_sg(req->con, req, rbuf, fr_en, + ret = rtrs_post_rdma_write_sg(req->con, req, rbuf, fr_en, count, req->usr_len + sizeof(*msg), imm, wr, &inv_wr); if (ret) { From ae8e70e31763634be736c928eaf7719295a70ab9 Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Thu, 18 Aug 2022 12:53:55 +0200 Subject: [PATCH 158/228] RDMA/rtrs-srv: Pass the correct number of entries for dma mapped SGL [ Upstream commit 56c310de0b4b3aca1c4fdd9c1093fc48372a7335 ] ib_dma_map_sg() augments the SGL into a 'dma mapped SGL'. This process may change the number of entries and the lengths of each entry. Code that touches dma_address is iterating over the 'dma mapped SGL' and must use dma_nents which returned from ib_dma_map_sg(). We should use the return count from ib_dma_map_sg for futher usage. Fixes: 9cb837480424e ("RDMA/rtrs: server: main functionality") Link: https://lore.kernel.org/r/20220818105355.110344-4-haris.iqbal@ionos.com Signed-off-by: Jack Wang Reviewed-by: Aleksei Marov Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/rtrs/rtrs-srv.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c index 1ca31b919e987..733116554e0bc 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c @@ -600,7 +600,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) struct sg_table *sgt = &srv_mr->sgt; struct scatterlist *s; struct ib_mr *mr; - int nr, chunks; + int nr, nr_sgt, chunks; chunks = chunks_per_mr * mri; if (!always_invalidate) @@ -615,19 +615,19 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) sg_set_page(s, srv->chunks[chunks + i], max_chunk_size, 0); - nr = ib_dma_map_sg(srv_path->s.dev->ib_dev, sgt->sgl, + nr_sgt = ib_dma_map_sg(srv_path->s.dev->ib_dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); - if (nr < sgt->nents) { - err = nr < 0 ? nr : -EINVAL; + if (!nr_sgt) { + err = -EINVAL; goto free_sg; } mr = ib_alloc_mr(srv_path->s.dev->ib_pd, IB_MR_TYPE_MEM_REG, - sgt->nents); + nr_sgt); if (IS_ERR(mr)) { err = PTR_ERR(mr); goto unmap_sg; } - nr = ib_map_mr_sg(mr, sgt->sgl, sgt->nents, + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, NULL, max_chunk_size); if (nr < 0 || nr < sgt->nents) { err = nr < 0 ? nr : -EINVAL; @@ -646,7 +646,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) } } /* Eventually dma addr for each chunk can be cached */ - for_each_sg(sgt->sgl, s, sgt->orig_nents, i) + for_each_sg(sgt->sgl, s, nr_sgt, i) srv_path->dma_addr[chunks + i] = sg_dma_address(s); ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); From 83a7e5d2f14e63dc095aea90c2db5e7b8cfa56f3 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 26 Jul 2022 15:05:21 +0200 Subject: [PATCH 159/228] ARM: dts: imx6qdl-kontron-samx6i: remove duplicated node [ Upstream commit 204f67d86f55dd4fa757ed04757d7273f71a169c ] The regulator node 'regulator-3p3v-s0' was dupplicated. Remove it to clean the DTS. Fixes: 2a51f9dae13d ("ARM: dts: imx6qdl-kontron-samx6i: Add iMX6-based Kontron SMARC-sAMX6i module") Signed-off-by: Marco Felsch Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi b/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi index b167b33bd108d..9a3e5f7827152 100644 --- a/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi +++ b/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi @@ -51,16 +51,6 @@ vin-supply = <®_3p3v_s5>; }; - reg_3p3v_s0: regulator-3p3v-s0 { - compatible = "regulator-fixed"; - regulator-name = "V_3V3_S0"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - vin-supply = <®_3p3v_s5>; - }; - reg_3p3v_s5: regulator-3p3v-s5 { compatible = "regulator-fixed"; regulator-name = "V_3V3_S5"; From a53b30716c607e8a8e036d765e41cd8a88d8205f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 12 Aug 2022 19:08:02 +0200 Subject: [PATCH 160/228] soc: imx: gpcv2: Assert reset before ungating clock [ Upstream commit df88005bd81b80c944d185554e264a4b0f993c37 ] In case the power domain clock are ungated before the reset is asserted, the system might freeze completely. This is likely due to a device is an undefined state being attached to bus, which sporadically leads to a bus hang. Assert the reset before the clock are enabled to assure the device is in defined state before being attached to bus. Fixes: fe58c887fb8ca ("soc: imx: gpcv2: add support for optional resets") Signed-off-by: Marek Vasut Reviewed-by: Fabio Estevam Reviewed-by: Lucas Stach Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- drivers/soc/imx/gpcv2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index b4aa28420f2a8..4dc3a3f73511e 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -237,6 +237,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd) } } + reset_control_assert(domain->reset); + /* Enable reset clocks for all devices in the domain */ ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); if (ret) { @@ -244,7 +246,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd) goto out_regulator_disable; } - reset_control_assert(domain->reset); + /* delays for reset to propagate */ + udelay(5); if (domain->bits.pxx) { /* request the domain to power up */ From eb53e84dc1ac3ceba101b33a955bd70a61a519fe Mon Sep 17 00:00:00 2001 From: Andrew Halaney Date: Fri, 19 Aug 2022 14:43:36 -0500 Subject: [PATCH 161/228] regulator: core: Clean up on enable failure [ Upstream commit c32f1ebfd26bece77141257864ed7b4720da1557 ] If regulator_enable() fails, enable_count is incremented still. A consumer, assuming no matching regulator_disable() is necessary on failure, will then get this error message upon regulator_put() since enable_count is non-zero: [ 1.277418] WARNING: CPU: 3 PID: 1 at drivers/regulator/core.c:2304 _regulator_put.part.0+0x168/0x170 The consumer could try to fix this in their driver by cleaning up on error from regulator_enable() (i.e. call regulator_disable()), but that results in the following since regulator_enable() failed and didn't increment user_count: [ 1.258112] unbalanced disables for vreg_l17c [ 1.262606] WARNING: CPU: 4 PID: 1 at drivers/regulator/core.c:2899 _regulator_disable+0xd4/0x190 Fix this by decrementing enable_count upon failure to enable. With this in place, just the reason for failure to enable is printed as expected and developers can focus on the root cause of their issue instead of thinking their usage of the regulator consumer api is incorrect. For example, in my case: [ 1.240426] vreg_l17c: invalid input voltage found Fixes: 5451781dadf8 ("regulator: core: Only count load for enabled consumers") Signed-off-by: Andrew Halaney Reviewed-by: Douglas Anderson Reviewed-by: Brian Masney Link: https://lore.kernel.org/r/20220819194336.382740-1-ahalaney@redhat.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f4f28e5888b1c..43613db7af754 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2688,13 +2688,18 @@ static int _regulator_do_enable(struct regulator_dev *rdev) */ static int _regulator_handle_consumer_enable(struct regulator *regulator) { + int ret; struct regulator_dev *rdev = regulator->rdev; lockdep_assert_held_once(&rdev->mutex.base); regulator->enable_count++; - if (regulator->uA_load && regulator->enable_count == 1) - return drms_uA_update(rdev); + if (regulator->uA_load && regulator->enable_count == 1) { + ret = drms_uA_update(rdev); + if (ret) + regulator->enable_count--; + return ret; + } return 0; } From e2ec1064a47dea9ea8e405c03307ad438ead2095 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Mon, 22 Aug 2022 07:43:35 +0200 Subject: [PATCH 162/228] tee: fix compiler warning in tee_shm_register() [ Upstream commit eccd7439709810127563e7e3e49b8b44c7b2791d ] Include to avoid the warning: drivers/tee/tee_shm.c: In function 'tee_shm_register': >> drivers/tee/tee_shm.c:242:14: error: implicit declaration of function 'access_ok' [-Werror=implicit-function-declaration] 242 | if (!access_ok((void __user *)addr, length)) | ^~~~~~~~~ cc1: some warnings being treated as errors Fixes: 573ae4f13f63 ("tee: add overflow check in register_shm_helper()") Reviewed-by: Sumit Garg Reported-by: kernel test robot Signed-off-by: Jens Wiklander Signed-off-by: Sasha Levin --- drivers/tee/tee_shm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 6e662fb131d55..bd96ebb82c8ec 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "tee_private.h" From d3eb252d763618fc7ba478fcbd548f455b3f85b2 Mon Sep 17 00:00:00 2001 From: Michael Guralnik Date: Tue, 23 Aug 2022 13:51:50 +0300 Subject: [PATCH 163/228] RDMA/cma: Fix arguments order in net device validation [ Upstream commit 27cfde795a96aef1e859a5480489944b95421e46 ] Fix the order of source and destination addresses when resolving the route between server and client to validate use of correct net device. The reverse order we had so far didn't actually validate the net device as the server would try to resolve the route to itself, thus always getting the server's net device. The issue was discovered when running cm applications on a single host between 2 interfaces with same subnet and source based routing rules. When resolving the reverse route the source based route rules were ignored. Fixes: f887f2ac87c2 ("IB/cma: Validate routing of incoming requests") Link: https://lore.kernel.org/r/1c1ec2277a131d277ebcceec987fd338d35b775f.1661251872.git.leonro@nvidia.com Signed-off-by: Michael Guralnik Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/core/cma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index a814dabcdff43..0da66dd40d6a8 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1718,8 +1718,8 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id, } if (!validate_net_dev(*net_dev, - (struct sockaddr *)&req->listen_addr_storage, - (struct sockaddr *)&req->src_addr_storage)) { + (struct sockaddr *)&req->src_addr_storage, + (struct sockaddr *)&req->listen_addr_storage)) { id_priv = ERR_PTR(-EHOSTUNREACH); goto err; } From 43245c77d9efd8c9eb91bf225d07954dcf32204d Mon Sep 17 00:00:00 2001 From: Liang He Date: Thu, 7 Jul 2022 09:56:20 +0800 Subject: [PATCH 164/228] soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugs [ Upstream commit 1085f5080647f0c9f357c270a537869191f7f2a1 ] In brcmstb_pm_probe(), there are two kinds of leak bugs: (1) we need to add of_node_put() when for_each__matching_node() breaks (2) we need to add iounmap() for each iomap in fail path Fixes: 0b741b8234c8 ("soc: bcm: brcmstb: Add support for S2/S3/S5 suspend states (ARM)") Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220707015620.306468-1-windhl@126.com Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/soc/bcm/brcmstb/pm/pm-arm.c | 50 ++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c index 70ad0f3dce283..286f5d57c0cab 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c @@ -684,13 +684,14 @@ static int brcmstb_pm_probe(struct platform_device *pdev) const struct of_device_id *of_id = NULL; struct device_node *dn; void __iomem *base; - int ret, i; + int ret, i, s; /* AON ctrl registers */ base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL); if (IS_ERR(base)) { pr_err("error mapping AON_CTRL\n"); - return PTR_ERR(base); + ret = PTR_ERR(base); + goto aon_err; } ctrl.aon_ctrl_base = base; @@ -700,8 +701,10 @@ static int brcmstb_pm_probe(struct platform_device *pdev) /* Assume standard offset */ ctrl.aon_sram = ctrl.aon_ctrl_base + AON_CTRL_SYSTEM_DATA_RAM_OFS; + s = 0; } else { ctrl.aon_sram = base; + s = 1; } writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC); @@ -711,7 +714,8 @@ static int brcmstb_pm_probe(struct platform_device *pdev) (const void **)&ddr_phy_data); if (IS_ERR(base)) { pr_err("error mapping DDR PHY\n"); - return PTR_ERR(base); + ret = PTR_ERR(base); + goto ddr_phy_err; } ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot; ctrl.pll_status_offset = ddr_phy_data->pll_status_offset; @@ -731,17 +735,20 @@ static int brcmstb_pm_probe(struct platform_device *pdev) for_each_matching_node(dn, ddr_shimphy_dt_ids) { i = ctrl.num_memc; if (i >= MAX_NUM_MEMC) { + of_node_put(dn); pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC); break; } base = of_io_request_and_map(dn, 0, dn->full_name); if (IS_ERR(base)) { + of_node_put(dn); if (!ctrl.support_warm_boot) break; pr_err("error mapping DDR SHIMPHY %d\n", i); - return PTR_ERR(base); + ret = PTR_ERR(base); + goto ddr_shimphy_err; } ctrl.memcs[i].ddr_shimphy_base = base; ctrl.num_memc++; @@ -752,14 +759,18 @@ static int brcmstb_pm_probe(struct platform_device *pdev) for_each_matching_node(dn, brcmstb_memc_of_match) { base = of_iomap(dn, 0); if (!base) { + of_node_put(dn); pr_err("error mapping DDR Sequencer %d\n", i); - return -ENOMEM; + ret = -ENOMEM; + goto brcmstb_memc_err; } of_id = of_match_node(brcmstb_memc_of_match, dn); if (!of_id) { iounmap(base); - return -EINVAL; + of_node_put(dn); + ret = -EINVAL; + goto brcmstb_memc_err; } ddr_seq_data = of_id->data; @@ -779,21 +790,24 @@ static int brcmstb_pm_probe(struct platform_device *pdev) dn = of_find_matching_node(NULL, sram_dt_ids); if (!dn) { pr_err("SRAM not found\n"); - return -EINVAL; + ret = -EINVAL; + goto brcmstb_memc_err; } ret = brcmstb_init_sram(dn); of_node_put(dn); if (ret) { pr_err("error setting up SRAM for PM\n"); - return ret; + goto brcmstb_memc_err; } ctrl.pdev = pdev; ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL); - if (!ctrl.s3_params) - return -ENOMEM; + if (!ctrl.s3_params) { + ret = -ENOMEM; + goto s3_params_err; + } ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params, sizeof(*ctrl.s3_params), DMA_TO_DEVICE); @@ -813,7 +827,21 @@ static int brcmstb_pm_probe(struct platform_device *pdev) out: kfree(ctrl.s3_params); - +s3_params_err: + iounmap(ctrl.boot_sram); +brcmstb_memc_err: + for (i--; i >= 0; i--) + iounmap(ctrl.memcs[i].ddr_ctrl); +ddr_shimphy_err: + for (i = 0; i < ctrl.num_memc; i++) + iounmap(ctrl.memcs[i].ddr_shimphy_base); + + iounmap(ctrl.memcs[0].ddr_phy_base); +ddr_phy_err: + iounmap(ctrl.aon_ctrl_base); + if (s) + iounmap(ctrl.aon_sram); +aon_err: pr_warn("PM: initialization failed with code %d\n", ret); return ret; From c1796dd542590e4122497deada6954990fcccad1 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Mon, 29 Aug 2022 18:50:18 +0800 Subject: [PATCH 165/228] RDMA/hns: Fix supported page size [ Upstream commit 55af9d498556f0860eb89ffa7677e8d73f6f643f ] The supported page size for hns is (4K, 128M), not (4K, 2G). Fixes: cfc85f3e4b7f ("RDMA/hns: Add profile support for hip08 driver") Link: https://lore.kernel.org/r/20220829105021.1427804-2-liangwenpeng@huawei.com Signed-off-by: Chengchang Tang Signed-off-by: Wenpeng Liang Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index df4501e77fd17..d3d5b5f57052c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -98,7 +98,7 @@ #define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ PAGE_SIZE #define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ PAGE_SIZE -#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED 0xFFFFF000 +#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED 0xFFFF000 #define HNS_ROCE_V2_MAX_INNER_MTPT_NUM 2 #define HNS_ROCE_INVALID_LKEY 0x0 #define HNS_ROCE_INVALID_SGE_LENGTH 0x80000000 From 6f7aa1029f8efc87457b7c5e7d6c3bcd12af101b Mon Sep 17 00:00:00 2001 From: Wenpeng Liang Date: Mon, 29 Aug 2022 18:50:19 +0800 Subject: [PATCH 166/228] RDMA/hns: Fix wrong fixed value of qp->rq.wqe_shift [ Upstream commit 0c8b5d6268d92d141bfd64d21c870d295a84dee1 ] The value of qp->rq.wqe_shift of HIP08 is always determined by the number of sge. So delete the wrong branch. Fixes: cfc85f3e4b7f ("RDMA/hns: Add profile support for hip08 driver") Fixes: 926a01dc000d ("RDMA/hns: Add QP operations support for hip08 SoC") Link: https://lore.kernel.org/r/20220829105021.1427804-3-liangwenpeng@huawei.com Signed-off-by: Wenpeng Liang Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_qp.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 9af4509894e68..5d50d2d1deca9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -495,11 +495,8 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap, hr_qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge) + hr_qp->rq.rsv_sge); - if (hr_dev->caps.max_rq_sg <= HNS_ROCE_SGE_IN_WQE) - hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz); - else - hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz * - hr_qp->rq.max_gs); + hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz * + hr_qp->rq.max_gs); hr_qp->rq.wqe_cnt = cnt; if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE && From 32dd0b22a5ba1dd296ccf2caf46ad44c3a8d5d98 Mon Sep 17 00:00:00 2001 From: "Ajay.Kathat@microchip.com" Date: Tue, 9 Aug 2022 07:57:56 +0000 Subject: [PATCH 167/228] wifi: wilc1000: fix DMA on stack objects [ Upstream commit 40b717bfcefab28a0656b8caa5e43d5449e5a671 ] Sometimes 'wilc_sdio_cmd53' is called with addresses pointing to an object on the stack. Use dynamically allocated memory for cmd53 instead of stack address which is not DMA'able. Fixes: 5625f965d764 ("wilc1000: move wilc driver out of staging") Reported-by: Michael Walle Suggested-by: Michael Walle Signed-off-by: Ajay Singh Reviewed-by: Michael Walle Tested-by: Michael Walle Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220809075749.62752-1-ajay.kathat@microchip.com Signed-off-by: Sasha Levin --- .../net/wireless/microchip/wilc1000/netdev.h | 1 + .../net/wireless/microchip/wilc1000/sdio.c | 39 ++++++++++++++++--- .../net/wireless/microchip/wilc1000/wlan.c | 15 ++++++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h index 86209b391a3d6..e6e23fc585ee8 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.h +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -252,6 +252,7 @@ struct wilc { u8 *rx_buffer; u32 rx_buffer_offset; u8 *tx_buffer; + u32 *vmm_table; struct txq_handle txq[NQUEUES]; int txq_entries; diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index 8b3b735231085..6c0727fc4abd9 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -27,6 +27,7 @@ struct wilc_sdio { bool irq_gpio; u32 block_size; int has_thrpt_enh3; + u8 *cmd53_buf; }; struct sdio_cmd52 { @@ -46,6 +47,7 @@ struct sdio_cmd53 { u32 count: 9; u8 *buffer; u32 block_size; + bool use_global_buf; }; static const struct wilc_hif_func wilc_hif_sdio; @@ -90,6 +92,8 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) { struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev); int size, ret; + struct wilc_sdio *sdio_priv = wilc->bus_data; + u8 *buf = cmd->buffer; sdio_claim_host(func); @@ -100,12 +104,23 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) else size = cmd->count; + if (cmd->use_global_buf) { + if (size > sizeof(u32)) + return -EINVAL; + + buf = sdio_priv->cmd53_buf; + } + if (cmd->read_write) { /* write */ - ret = sdio_memcpy_toio(func, cmd->address, - (void *)cmd->buffer, size); + if (cmd->use_global_buf) + memcpy(buf, cmd->buffer, size); + + ret = sdio_memcpy_toio(func, cmd->address, buf, size); } else { /* read */ - ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, - cmd->address, size); + ret = sdio_memcpy_fromio(func, buf, cmd->address, size); + + if (cmd->use_global_buf) + memcpy(cmd->buffer, buf, size); } sdio_release_host(func); @@ -127,6 +142,12 @@ static int wilc_sdio_probe(struct sdio_func *func, if (!sdio_priv) return -ENOMEM; + sdio_priv->cmd53_buf = kzalloc(sizeof(u32), GFP_KERNEL); + if (!sdio_priv->cmd53_buf) { + ret = -ENOMEM; + goto free; + } + ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO, &wilc_hif_sdio); if (ret) @@ -160,6 +181,7 @@ static int wilc_sdio_probe(struct sdio_func *func, irq_dispose_mapping(wilc->dev_irq_num); wilc_netdev_cleanup(wilc); free: + kfree(sdio_priv->cmd53_buf); kfree(sdio_priv); return ret; } @@ -171,6 +193,7 @@ static void wilc_sdio_remove(struct sdio_func *func) clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); + kfree(sdio_priv->cmd53_buf); kfree(sdio_priv); } @@ -367,8 +390,9 @@ static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data) cmd.address = WILC_SDIO_FBR_DATA_REG; cmd.block_mode = 0; cmd.increment = 1; - cmd.count = 4; + cmd.count = sizeof(u32); cmd.buffer = (u8 *)&data; + cmd.use_global_buf = true; cmd.block_size = sdio_priv->block_size; ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) @@ -406,6 +430,7 @@ static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) nblk = size / block_size; nleft = size % block_size; + cmd.use_global_buf = false; if (nblk > 0) { cmd.block_mode = 1; cmd.increment = 1; @@ -484,8 +509,9 @@ static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) cmd.address = WILC_SDIO_FBR_DATA_REG; cmd.block_mode = 0; cmd.increment = 1; - cmd.count = 4; + cmd.count = sizeof(u32); cmd.buffer = (u8 *)data; + cmd.use_global_buf = true; cmd.block_size = sdio_priv->block_size; ret = wilc_sdio_cmd53(wilc, &cmd); @@ -527,6 +553,7 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) nblk = size / block_size; nleft = size % block_size; + cmd.use_global_buf = false; if (nblk > 0) { cmd.block_mode = 1; cmd.increment = 1; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 200a103a0a858..380699983a75b 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -701,7 +701,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) int ret = 0; int counter; int timeout; - u32 vmm_table[WILC_VMM_TBL_SIZE]; + u32 *vmm_table = wilc->vmm_table; u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0}; const struct wilc_hif_func *func; int srcu_idx; @@ -1220,6 +1220,8 @@ void wilc_wlan_cleanup(struct net_device *dev) while ((rqe = wilc_wlan_rxq_remove(wilc))) kfree(rqe); + kfree(wilc->vmm_table); + wilc->vmm_table = NULL; kfree(wilc->rx_buffer); wilc->rx_buffer = NULL; kfree(wilc->tx_buffer); @@ -1455,6 +1457,14 @@ int wilc_wlan_init(struct net_device *dev) goto fail; } + if (!wilc->vmm_table) + wilc->vmm_table = kzalloc(WILC_VMM_TBL_SIZE, GFP_KERNEL); + + if (!wilc->vmm_table) { + ret = -ENOBUFS; + goto fail; + } + if (!wilc->tx_buffer) wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL); @@ -1479,7 +1489,8 @@ int wilc_wlan_init(struct net_device *dev) return 0; fail: - + kfree(wilc->vmm_table); + wilc->vmm_table = NULL; kfree(wilc->rx_buffer); wilc->rx_buffer = NULL; kfree(wilc->tx_buffer); From e11d08c825f254ca1bbc529419bafefb1a59c9a6 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:20 +0300 Subject: [PATCH 168/228] ARM: at91: pm: fix self-refresh for sama7g5 [ Upstream commit a02875c4cbd6f3d2f33d70cc158a19ef02d4b84f ] It has been discovered that on some parts, from time to time, self-refresh procedure doesn't work as expected. Debugging and investigating it proved that disabling AC DLL introduce glitches in RAM controllers which leads to unexpected behavior. This is confirmed as a hardware bug. DLL bypass disables 3 DLLs: 2 DX DLLs and AC DLL. Thus, keep only DX DLLs disabled. This introduce 6mA extra current consumption on VDDCORE when switching to any ULP mode or standby mode but the self-refresh procedure still works. Fixes: f0bbf17958e8 ("ARM: at91: pm: add self-refresh support for sama7g5") Suggested-by: Frederic Schumacher Signed-off-by: Claudiu Beznea Tested-by: Cristian Birsan Link: https://lore.kernel.org/r/20220826083927.3107272-3-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/mach-at91/pm_suspend.S | 24 +++++++++++++++++------- include/soc/at91/sama7-ddr.h | 4 ++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index fdb4f63ecde4b..65cfcc19a936c 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -172,9 +172,15 @@ sr_ena_2: /* Put DDR PHY's DLL in bypass mode for non-backup modes. */ cmp r7, #AT91_PM_BACKUP beq sr_ena_3 - ldr tmp1, [r3, #DDR3PHY_PIR] - orr tmp1, tmp1, #DDR3PHY_PIR_DLLBYP - str tmp1, [r3, #DDR3PHY_PIR] + + /* Disable DX DLLs. */ + ldr tmp1, [r3, #DDR3PHY_DX0DLLCR] + orr tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS + str tmp1, [r3, #DDR3PHY_DX0DLLCR] + + ldr tmp1, [r3, #DDR3PHY_DX1DLLCR] + orr tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS + str tmp1, [r3, #DDR3PHY_DX1DLLCR] sr_ena_3: /* Power down DDR PHY data receivers. */ @@ -221,10 +227,14 @@ sr_ena_3: bic tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0 str tmp1, [r3, #DDR3PHY_DSGCR] - /* Take DDR PHY's DLL out of bypass mode. */ - ldr tmp1, [r3, #DDR3PHY_PIR] - bic tmp1, tmp1, #DDR3PHY_PIR_DLLBYP - str tmp1, [r3, #DDR3PHY_PIR] + /* Enable DX DLLs. */ + ldr tmp1, [r3, #DDR3PHY_DX0DLLCR] + bic tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS + str tmp1, [r3, #DDR3PHY_DX0DLLCR] + + ldr tmp1, [r3, #DDR3PHY_DX1DLLCR] + bic tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS + str tmp1, [r3, #DDR3PHY_DX1DLLCR] /* Enable quasi-dynamic programming. */ mov tmp1, #0 diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h index f6542584ca139..f47a933df82ea 100644 --- a/include/soc/at91/sama7-ddr.h +++ b/include/soc/at91/sama7-ddr.h @@ -41,6 +41,10 @@ #define DDR3PHY_ZQ0SR0 (0x188) /* ZQ status register 0 */ +#define DDR3PHY_DX0DLLCR (0x1CC) /* DDR3PHY DATX8 DLL Control Register */ +#define DDR3PHY_DX1DLLCR (0x20C) /* DDR3PHY DATX8 DLL Control Register */ +#define DDR3PHY_DXDLLCR_DLLDIS (1 << 31) /* DLL Disable */ + /* UDDRC */ #define UDDRC_STAT (0x04) /* UDDRC Operating Mode Status Register */ #define UDDRC_STAT_SELFREF_TYPE_DIS (0x0 << 4) /* SDRAM is not in Self-refresh */ From 6fbff44cba17bcba935b31e1689d8e31410b4ebb Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:21 +0300 Subject: [PATCH 169/228] ARM: at91: pm: fix DDR recalibration when resuming from backup and self-refresh [ Upstream commit 7a94b83a7dc551607b6c4400df29151e6a951f07 ] On SAMA7G5, when resuming from backup and self-refresh, the bootloader performs DDR PHY recalibration by restoring the value of ZQ0SR0 (stored in RAM by Linux before going to backup and self-refresh). It has been discovered that the current procedure doesn't work for all possible values that might go to ZQ0SR0 due to hardware bug. The workaround to this is to avoid storing some values in ZQ0SR0. Thus Linux will read the ZQ0SR0 register and cache its value in RAM after processing it (using modified_gray_code array). The bootloader will restore the processed value. Fixes: d2d4716d8384 ("ARM: at91: pm: save ddr phy calibration data to securam") Suggested-by: Frederic Schumacher Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220826083927.3107272-4-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/mach-at91/pm.c | 36 ++++++++++++++++++++++++++++++++---- include/soc/at91/sama7-ddr.h | 4 ++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index ed1050404ef0a..c8cc993ca8ca1 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -350,9 +350,41 @@ extern u32 at91_pm_suspend_in_sram_sz; static int at91_suspend_finish(unsigned long val) { + unsigned char modified_gray_code[] = { + 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b, + 0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, + 0x10, 0x11, + }; + unsigned int tmp, index; int i; if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) { + /* + * Bootloader will perform DDR recalibration and will try to + * restore the ZQ0SR0 with the value saved here. But the + * calibration is buggy and restoring some values from ZQ0SR0 + * is forbidden and risky thus we need to provide processed + * values for these (modified gray code values). + */ + tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0); + + /* Store pull-down output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f; + soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index]; + + /* Store pull-up output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f; + soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; + + /* Store pull-down on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f; + soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; + + /* Store pull-up on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f; + soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; + /* * The 1st 8 words of memory might get corrupted in the process * of DDR PHY recalibration; it is saved here in securam and it @@ -841,10 +873,6 @@ static int __init at91_pm_backup_init(void) of_scan_flat_dt(at91_pm_backup_scan_memcs, &located); if (!located) goto securam_fail; - - /* DDR3PHY_ZQ0SR0 */ - soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + - 0x188); } return 0; diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h index f47a933df82ea..72d19887ab810 100644 --- a/include/soc/at91/sama7-ddr.h +++ b/include/soc/at91/sama7-ddr.h @@ -40,6 +40,10 @@ #define DDR3PHY_DSGCR_ODTPDD_ODT0 (1 << 20) /* ODT[0] Power Down Driver */ #define DDR3PHY_ZQ0SR0 (0x188) /* ZQ status register 0 */ +#define DDR3PHY_ZQ0SR0_PDO_OFF (0) /* Pull-down output impedance select offset */ +#define DDR3PHY_ZQ0SR0_PUO_OFF (5) /* Pull-up output impedance select offset */ +#define DDR3PHY_ZQ0SR0_PDODT_OFF (10) /* Pull-down on-die termination impedance select offset */ +#define DDR3PHY_ZQ0SRO_PUODT_OFF (15) /* Pull-up on-die termination impedance select offset */ #define DDR3PHY_DX0DLLCR (0x1CC) /* DDR3PHY DATX8 DLL Control Register */ #define DDR3PHY_DX1DLLCR (0x20C) /* DDR3PHY DATX8 DLL Control Register */ From a8ab10c3f137f3f2a3aa900a6c0371091458bf90 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:22 +0300 Subject: [PATCH 170/228] ARM: dts: at91: sama5d27_wlsom1: specify proper regulator output ranges [ Upstream commit addf7efec23af2b67547800aa232d551945e7de2 ] Min and max output ranges of regulators need to satisfy board requirements not PMIC requirements. Thus adjust device tree to cope with this. Fixes: 5d4c3cfb63fe ("ARM: dts: at91: sama5d27_wlsom1: add SAMA5D27 wlsom1 and wlsom1-ek") Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220826083927.3107272-5-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi b/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi index 025a78310e3ab..70513caf3e8d0 100644 --- a/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi +++ b/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi @@ -68,8 +68,8 @@ regulators { vdd_3v3: VDD_IO { regulator-name = "VDD_IO"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -87,8 +87,8 @@ vddio_ddr: VDD_DDR { regulator-name = "VDD_DDR"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1850000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -110,8 +110,8 @@ vdd_core: VDD_CORE { regulator-name = "VDD_CORE"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1850000>; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -152,8 +152,8 @@ LDO1 { regulator-name = "LDO1"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-always-on; regulator-state-standby { @@ -167,8 +167,8 @@ LDO2 { regulator-name = "LDO2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; regulator-always-on; regulator-state-standby { From d6015c56f4773dcebac1e6e3ca321e3e1e3bf633 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:23 +0300 Subject: [PATCH 171/228] ARM: dts: at91: sama5d2_icp: specify proper regulator output ranges [ Upstream commit 7737d93666eea282febf95e5fa3b3fde1f2549f3 ] Min and max output ranges of regulators need to satisfy board requirements not PMIC requirements. Thus adjust device tree to cope with this. Fixes: 68a95ef72cef ("ARM: dts: at91: sama5d2-icp: add SAMA5D2-ICP") Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220826083927.3107272-6-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/boot/dts/at91-sama5d2_icp.dts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_icp.dts b/arch/arm/boot/dts/at91-sama5d2_icp.dts index fd1a288f686bc..c175237b6d4e4 100644 --- a/arch/arm/boot/dts/at91-sama5d2_icp.dts +++ b/arch/arm/boot/dts/at91-sama5d2_icp.dts @@ -197,8 +197,8 @@ regulators { vdd_io_reg: VDD_IO { regulator-name = "VDD_IO"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -216,8 +216,8 @@ VDD_DDR { regulator-name = "VDD_DDR"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1850000>; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -235,8 +235,8 @@ VDD_CORE { regulator-name = "VDD_CORE"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1850000>; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; regulator-always-on; @@ -273,8 +273,8 @@ LDO1 { regulator-name = "LDO1"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; regulator-always-on; regulator-state-standby { @@ -288,8 +288,8 @@ LDO2 { regulator-name = "LDO2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3700000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-always-on; regulator-state-standby { From 86706fa90be6d5f487d6bc19af5c0ccb1a89644e Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:25 +0300 Subject: [PATCH 172/228] ARM: dts: at91: sama5d27_wlsom1: don't keep ldo2 enabled all the time [ Upstream commit 617a0d9fe6867bf5b3b7272629cd780c27c877d9 ] ldo2 is not used by any consumer on sama5d27_wlsom1 board, thus don't keep it enabled all the time. Fixes: 5d4c3cfb63fe ("ARM: dts: at91: sama5d27_wlsom1: add SAMA5D27 wlsom1 and wlsom1-ek") Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220826083927.3107272-8-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi b/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi index 70513caf3e8d0..a818e8ebd638f 100644 --- a/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi +++ b/arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi @@ -169,7 +169,6 @@ regulator-name = "LDO2"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; - regulator-always-on; regulator-state-standby { regulator-on-in-suspend; From 940e58f2ccc060b9d5fa3fa529c1ff6c620e39a4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 26 Aug 2022 11:39:26 +0300 Subject: [PATCH 173/228] ARM: dts: at91: sama5d2_icp: don't keep vdd_other enabled all the time [ Upstream commit 3d074b750d2b4c91962f10ea1df1c289ce0d3ce8 ] VDD_OTHER is not connected to any on board consumer thus it is not needed to keep it enabled all the time. Fixes: 68a95ef72cef ("ARM: dts: at91: sama5d2-icp: add SAMA5D2-ICP") Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220826083927.3107272-9-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- arch/arm/boot/dts/at91-sama5d2_icp.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_icp.dts b/arch/arm/boot/dts/at91-sama5d2_icp.dts index c175237b6d4e4..4ebbbe65c0cee 100644 --- a/arch/arm/boot/dts/at91-sama5d2_icp.dts +++ b/arch/arm/boot/dts/at91-sama5d2_icp.dts @@ -258,7 +258,6 @@ regulator-max-microvolt = <1850000>; regulator-initial-mode = <2>; regulator-allowed-modes = <2>, <4>; - regulator-always-on; regulator-state-standby { regulator-on-in-suspend; From 92837ac047790061826c4dbaff03b19beb7be9cf Mon Sep 17 00:00:00 2001 From: Harsh Modi Date: Tue, 30 Aug 2022 22:36:03 -0700 Subject: [PATCH 174/228] netfilter: br_netfilter: Drop dst references before setting. [ Upstream commit d047283a7034140ea5da759a494fd2274affdd46 ] The IPv6 path already drops dst in the daddr changed case, but the IPv4 path does not. This change makes the two code paths consistent. Further, it is possible that there is already a metadata_dst allocated from ingress that might already be attached to skbuff->dst while following the bridge path. If it is not released before setting a new metadata_dst, it will be leaked. This is similar to what is done in bpf_set_tunnel_key() or ip6_route_input(). It is important to note that the memory being leaked is not the dst being set in the bridge code, but rather memory allocated from some other code path that is not being freed correctly before the skb dst is overwritten. An example of the leakage fixed by this commit found using kmemleak: unreferenced object 0xffff888010112b00 (size 256): comm "softirq", pid 0, jiffies 4294762496 (age 32.012s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 80 16 f1 83 ff ff ff ff ................ e1 4e f6 82 ff ff ff ff 00 00 00 00 00 00 00 00 .N.............. backtrace: [<00000000d79567ea>] metadata_dst_alloc+0x1b/0xe0 [<00000000be113e13>] udp_tun_rx_dst+0x174/0x1f0 [<00000000a36848f4>] geneve_udp_encap_recv+0x350/0x7b0 [<00000000d4afb476>] udp_queue_rcv_one_skb+0x380/0x560 [<00000000ac064aea>] udp_unicast_rcv_skb+0x75/0x90 [<000000009a8ee8c5>] ip_protocol_deliver_rcu+0xd8/0x230 [<00000000ef4980bb>] ip_local_deliver_finish+0x7a/0xa0 [<00000000d7533c8c>] __netif_receive_skb_one_core+0x89/0xa0 [<00000000a879497d>] process_backlog+0x93/0x190 [<00000000e41ade9f>] __napi_poll+0x28/0x170 [<00000000b4c0906b>] net_rx_action+0x14f/0x2a0 [<00000000b20dd5d4>] __do_softirq+0xf4/0x305 [<000000003a7d7e15>] __irq_exit_rcu+0xc3/0x140 [<00000000968d39a2>] sysvec_apic_timer_interrupt+0x9e/0xc0 [<000000009e920794>] asm_sysvec_apic_timer_interrupt+0x16/0x20 [<000000008942add0>] native_safe_halt+0x13/0x20 Florian Westphal says: "Original code was likely fine because nothing ever did set a skb->dst entry earlier than bridge in those days." Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Harsh Modi Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/bridge/br_netfilter_hooks.c | 2 ++ net/bridge/br_netfilter_ipv6.c | 1 + 2 files changed, 3 insertions(+) diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 10a2c7bca7199..a718204c4bfdd 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -384,6 +384,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_ /* - Bridged-and-DNAT'ed traffic doesn't * require ip_forwarding. */ if (rt->dst.dev == dev) { + skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); goto bridged_dnat; } @@ -413,6 +414,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_ kfree_skb(skb); return 0; } + skb_dst_drop(skb); skb_dst_set_noref(skb, &rt->dst); } diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index e4e0c836c3f51..6b07f30675bb0 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c @@ -197,6 +197,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc kfree_skb(skb); return 0; } + skb_dst_drop(skb); skb_dst_set_noref(skb, &rt->dst); } From 1ce55ec5cb7c573c983dffbe290b8d17caf1f157 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 31 Aug 2022 13:11:47 +0200 Subject: [PATCH 175/228] netfilter: nf_tables: clean up hook list when offload flags check fails [ Upstream commit 77972a36ecc4db7fc7c68f0e80714263c5f03f65 ] splice back the hook list so nft_chain_release_hook() has a chance to release the hooks. BUG: memory leak unreferenced object 0xffff88810180b100 (size 96): comm "syz-executor133", pid 3619, jiffies 4294945714 (age 12.690s) hex dump (first 32 bytes): 28 64 23 02 81 88 ff ff 28 64 23 02 81 88 ff ff (d#.....(d#..... 90 a8 aa 83 ff ff ff ff 00 00 b5 0f 81 88 ff ff ................ backtrace: [] kmalloc include/linux/slab.h:600 [inline] [] nft_netdev_hook_alloc+0x3b/0xc0 net/netfilter/nf_tables_api.c:1901 [] nft_chain_parse_netdev net/netfilter/nf_tables_api.c:1998 [inline] [] nft_chain_parse_hook+0x33a/0x530 net/netfilter/nf_tables_api.c:2073 [] nf_tables_addchain.constprop.0+0x10b/0x950 net/netfilter/nf_tables_api.c:2218 [] nf_tables_newchain+0xa8b/0xc60 net/netfilter/nf_tables_api.c:2593 [] nfnetlink_rcv_batch+0xa46/0xd20 net/netfilter/nfnetlink.c:517 [] nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:638 [inline] [] nfnetlink_rcv+0x1f9/0x220 net/netfilter/nfnetlink.c:656 [] netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline] [] netlink_unicast+0x397/0x4c0 net/netlink/af_netlink.c:1345 [] netlink_sendmsg+0x396/0x710 net/netlink/af_netlink.c:1921 [] sock_sendmsg_nosec net/socket.c:714 [inline] [] sock_sendmsg+0x56/0x80 net/socket.c:734 [] ____sys_sendmsg+0x36c/0x390 net/socket.c:2482 [] ___sys_sendmsg+0xa8/0x110 net/socket.c:2536 [] __sys_sendmsg+0x88/0x100 net/socket.c:2565 [] do_syscall_x64 arch/x86/entry/common.c:50 [inline] [] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 [] entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: d54725cd11a5 ("netfilter: nf_tables: support for multiple devices per netdev hook") Reported-by: syzbot+5fcdbfab6d6744c57418@syzkaller.appspotmail.com Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d8ca55d6be409..d35d09df83fee 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2072,8 +2072,10 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family, chain->flags |= NFT_CHAIN_BASE | flags; basechain->policy = NF_ACCEPT; if (chain->flags & NFT_CHAIN_HW_OFFLOAD && - !nft_chain_offload_support(basechain)) + !nft_chain_offload_support(basechain)) { + list_splice_init(&basechain->hook_list, &hook->list); return -EOPNOTSUPP; + } flow_block_init(&basechain->flow_block); From 451c9ce1e2fc9b9e40303bef8e5a0dca1a923cc4 Mon Sep 17 00:00:00 2001 From: David Leadbeater Date: Fri, 26 Aug 2022 14:56:58 +1000 Subject: [PATCH 176/228] netfilter: nf_conntrack_irc: Fix forged IP logic [ Upstream commit 0efe125cfb99e6773a7434f3463f7c2fa28f3a43 ] Ensure the match happens in the right direction, previously the destination used was the server, not the NAT host, as the comment shows the code intended. Additionally nf_nat_irc uses port 0 as a signal and there's no valid way it can appear in a DCC message, so consider port 0 also forged. Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") Signed-off-by: David Leadbeater Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_irc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 08ee4e760a3d2..18b90e334b5bd 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -188,8 +188,9 @@ static int help(struct sk_buff *skb, unsigned int protoff, /* dcc_ip can be the internal OR external (NAT'ed) IP */ tuple = &ct->tuplehash[dir].tuple; - if (tuple->src.u3.ip != dcc_ip && - tuple->dst.u3.ip != dcc_ip) { + if ((tuple->src.u3.ip != dcc_ip && + ct->tuplehash[!dir].tuple.dst.u3.ip != dcc_ip) || + dcc_port == 0) { net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", &tuple->src.u3.ip, &dcc_ip, dcc_port); From a8edd49c94b4b08019ed7d6dd794fca8078a4deb Mon Sep 17 00:00:00 2001 From: "yangx.jy@fujitsu.com" Date: Wed, 31 Aug 2022 08:16:29 +0000 Subject: [PATCH 177/228] RDMA/srp: Set scmnd->result only when scmnd is not NULL [ Upstream commit 12f35199a2c0551187edbf8eb01379f0598659fa ] This change fixes the following kernel NULL pointer dereference which is reproduced by blktests srp/007 occasionally. BUG: kernel NULL pointer dereference, address: 0000000000000170 PGD 0 P4D 0 Oops: 0002 [#1] PREEMPT SMP NOPTI CPU: 0 PID: 9 Comm: kworker/0:1H Kdump: loaded Not tainted 6.0.0-rc1+ #37 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-29-g6a62e0cb0dfe-prebuilt.qemu.org 04/01/2014 Workqueue: 0x0 (kblockd) RIP: 0010:srp_recv_done+0x176/0x500 [ib_srp] Code: 00 4d 85 ff 0f 84 52 02 00 00 48 c7 82 80 02 00 00 00 00 00 00 4c 89 df 4c 89 14 24 e8 53 d3 4a f6 4c 8b 14 24 41 0f b6 42 13 <41> 89 87 70 01 00 00 41 0f b6 52 12 f6 c2 02 74 44 41 8b 42 1c b9 RSP: 0018:ffffaef7c0003e28 EFLAGS: 00000282 RAX: 0000000000000000 RBX: ffff9bc9486dea60 RCX: 0000000000000000 RDX: 0000000000000102 RSI: ffffffffb76bbd0e RDI: 00000000ffffffff RBP: ffff9bc980099a00 R08: 0000000000000001 R09: 0000000000000001 R10: ffff9bca53ef0000 R11: ffff9bc980099a10 R12: ffff9bc956e14000 R13: ffff9bc9836b9cb0 R14: ffff9bc9557b4480 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff9bc97ec00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000170 CR3: 0000000007e04000 CR4: 00000000000006f0 Call Trace: __ib_process_cq+0xb7/0x280 [ib_core] ib_poll_handler+0x2b/0x130 [ib_core] irq_poll_softirq+0x93/0x150 __do_softirq+0xee/0x4b8 irq_exit_rcu+0xf7/0x130 sysvec_apic_timer_interrupt+0x8e/0xc0 Fixes: ad215aaea4f9 ("RDMA/srp: Make struct scsi_cmnd and struct srp_request adjacent") Link: https://lore.kernel.org/r/20220831081626.18712-1-yangx.jy@fujitsu.com Signed-off-by: Xiao Yang Acked-by: Bart Van Assche Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/srp/ib_srp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5d416ec228717..473b3a08cf96d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1955,7 +1955,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) if (scmnd) { req = scsi_cmd_priv(scmnd); scmnd = srp_claim_req(ch, req, NULL, scmnd); - } else { + } + if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n", rsp->tag, ch - target->ch, ch->qp->qp_num); From 4dc401ef8b23fc4ae463959ae7c26b7a18bb9ceb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Aug 2022 14:59:00 +0200 Subject: [PATCH 178/228] ALSA: usb-audio: Inform the delayed registration more properly [ Upstream commit 7e1afce5866e02b45bf88c27dd7de1b9dfade1cc ] The info message that was added in the commit a4aad5636c72 ("ALSA: usb-audio: Inform devices that need delayed registration") is actually useful to know the need for the delayed registration. However, it turned out that this doesn't catch the all cases; namely, this warned only when a PCM stream is attached onto the existing PCM instance, but it doesn't count for a newly created PCM instance. This made confusion as if there were no further delayed registration. This patch moves the check to the code path for either adding a stream or creating a PCM instance. Also, make it simpler by checking the card->registered flag instead of querying each snd_device state. Fixes: a4aad5636c72 ("ALSA: usb-audio: Inform devices that need delayed registration") Link: https://bugzilla.kernel.org/show_bug.cgi?id=216082 Link: https://lore.kernel.org/r/20220831125901.4660-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/stream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 40ce8a1cb318a..f10f4e6d3fb85 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -495,6 +495,10 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, return 0; } } + + if (chip->card->registered) + chip->need_delayed_register = true; + /* look for an empty stream */ list_for_each_entry(as, &chip->pcm_list, list) { if (as->fmt_type != fp->fmt_type) @@ -502,9 +506,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, subs = &as->substream[stream]; if (subs->ep_num) continue; - if (snd_device_get_state(chip->card, as->pcm) != - SNDRV_DEV_BUILD) - chip->need_delayed_register = true; err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) return err; From 59f1c62d91cab10e8378330b4dd58d5ba233cd82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Aug 2022 14:59:01 +0200 Subject: [PATCH 179/228] ALSA: usb-audio: Register card again for iface over delayed_register option [ Upstream commit 2027f114686e0f3f1f39971964dfc618637c88c2 ] When the delayed registration is specified via either delayed_register option or the quirk, we delay the invocation of snd_card_register() until the given interface. But if a wrong value has been set there and there are more interfaces over the given interface number, snd_card_register() call would be missing for those interfaces. This patch catches up those missing calls by fixing the comparison of the interface number. Now the call is skipped only if the processed interface is less than the given interface, instead of the exact match. Fixes: b70038ef4fea ("ALSA: usb-audio: Add delayed_register option") Link: https://bugzilla.kernel.org/show_bug.cgi?id=216082 Link: https://lore.kernel.org/r/20220831125901.4660-2-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/card.c | 2 +- sound/usb/quirks.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index ff5f8de1bc540..713b84d8d42f1 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -698,7 +698,7 @@ static bool check_delayed_register_option(struct snd_usb_audio *chip, int iface) if (delayed_register[i] && sscanf(delayed_register[i], "%x:%x", &id, &inum) == 2 && id == chip->usb_id) - return inum != iface; + return iface < inum; } return false; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9bfead5efc4c1..5b4d8f5eade20 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1764,7 +1764,7 @@ bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface) for (q = registration_quirks; q->usb_id; q++) if (chip->usb_id == q->usb_id) - return iface != q->interface; + return iface < q->interface; /* Register as normal */ return false; From 24a4e79d92e0027ed5e44d589b9540d97314b368 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 26 Aug 2022 15:39:28 +0100 Subject: [PATCH 180/228] rxrpc: Fix ICMP/ICMP6 error handling [ Upstream commit ac56a0b48da86fd1b4389632fb7c4c8a5d86eefa ] Because rxrpc pretends to be a tunnel on top of a UDP/UDP6 socket, allowing it to siphon off UDP packets early in the handling of received UDP packets thereby avoiding the packet going through the UDP receive queue, it doesn't get ICMP packets through the UDP ->sk_error_report() callback. In fact, it doesn't appear that there's any usable option for getting hold of ICMP packets. Fix this by adding a new UDP encap hook to distribute error messages for UDP tunnels. If the hook is set, then the tunnel driver will be able to see ICMP packets. The hook provides the offset into the packet of the UDP header of the original packet that caused the notification. An alternative would be to call the ->error_handler() hook - but that requires that the skbuff be cloned (as ip_icmp_error() or ipv6_cmp_error() do, though isn't really necessary or desirable in rxrpc's case is we want to parse them there and then, not queue them). Changes ======= ver #3) - Fixed an uninitialised variable. ver #2) - Fixed some missing CONFIG_AF_RXRPC_IPV6 conditionals. Fixes: 5271953cad31 ("rxrpc: Use the UDP encap_rcv hook") Signed-off-by: David Howells Signed-off-by: Sasha Levin --- include/linux/udp.h | 1 + include/net/udp_tunnel.h | 4 + net/ipv4/udp.c | 2 + net/ipv4/udp_tunnel_core.c | 1 + net/ipv6/udp.c | 5 +- net/rxrpc/ar-internal.h | 1 + net/rxrpc/local_object.c | 1 + net/rxrpc/peer_event.c | 293 ++++++++++++++++++++++++++++++++----- 8 files changed, 270 insertions(+), 38 deletions(-) diff --git a/include/linux/udp.h b/include/linux/udp.h index ae66dadd85434..0727276e7538c 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -75,6 +75,7 @@ struct udp_sock { * For encapsulation sockets. */ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); + void (*encap_err_rcv)(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset); int (*encap_err_lookup)(struct sock *sk, struct sk_buff *skb); void (*encap_destroy)(struct sock *sk); diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index afc7ce713657b..72394f441dad8 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -67,6 +67,9 @@ static inline int udp_sock_create(struct net *net, typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb); typedef int (*udp_tunnel_encap_err_lookup_t)(struct sock *sk, struct sk_buff *skb); +typedef void (*udp_tunnel_encap_err_rcv_t)(struct sock *sk, + struct sk_buff *skb, + unsigned int udp_offset); typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk); typedef struct sk_buff *(*udp_tunnel_gro_receive_t)(struct sock *sk, struct list_head *head, @@ -80,6 +83,7 @@ struct udp_tunnel_sock_cfg { __u8 encap_type; udp_tunnel_encap_rcv_t encap_rcv; udp_tunnel_encap_err_lookup_t encap_err_lookup; + udp_tunnel_encap_err_rcv_t encap_err_rcv; udp_tunnel_encap_destroy_t encap_destroy; udp_tunnel_gro_receive_t gro_receive; udp_tunnel_gro_complete_t gro_complete; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index efef7ba44e1d6..75d1977ecc07e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -781,6 +781,8 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) */ if (tunnel) { /* ...not for tunnels though: we don't have a sending socket */ + if (udp_sk(sk)->encap_err_rcv) + udp_sk(sk)->encap_err_rcv(sk, skb, iph->ihl << 2); goto out; } if (!inet->recverr) { diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index b97e3635acf50..46101fd67a477 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -75,6 +75,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, udp_sk(sk)->encap_type = cfg->encap_type; udp_sk(sk)->encap_rcv = cfg->encap_rcv; + udp_sk(sk)->encap_err_rcv = cfg->encap_err_rcv; udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup; udp_sk(sk)->encap_destroy = cfg->encap_destroy; udp_sk(sk)->gro_receive = cfg->gro_receive; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4a9afdbd5f292..07726a51a3f09 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -614,8 +614,11 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, } /* Tunnels don't have an application socket: don't pass errors back */ - if (tunnel) + if (tunnel) { + if (udp_sk(sk)->encap_err_rcv) + udp_sk(sk)->encap_err_rcv(sk, skb, offset); goto out; + } if (!np->recverr) { if (!harderr || sk->sk_state != TCP_ESTABLISHED) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index f2d593e27b64f..f2e3fb77a02d3 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -990,6 +990,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *); /* * peer_event.c */ +void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset); void rxrpc_error_report(struct sock *); void rxrpc_peer_keepalive_worker(struct work_struct *); diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 6a1611b0e3037..ef43fe8bdd2ff 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -137,6 +137,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) tuncfg.encap_type = UDP_ENCAP_RXRPC; tuncfg.encap_rcv = rxrpc_input_packet; + tuncfg.encap_err_rcv = rxrpc_encap_err_rcv; tuncfg.sk_user_data = local; setup_udp_tunnel_sock(net, local->socket, &tuncfg); diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c index be032850ae8ca..32561e9567fe3 100644 --- a/net/rxrpc/peer_event.c +++ b/net/rxrpc/peer_event.c @@ -16,22 +16,105 @@ #include #include #include +#include #include "ar-internal.h" +static void rxrpc_adjust_mtu(struct rxrpc_peer *, unsigned int); static void rxrpc_store_error(struct rxrpc_peer *, struct sock_exterr_skb *); static void rxrpc_distribute_error(struct rxrpc_peer *, int, enum rxrpc_call_completion); /* - * Find the peer associated with an ICMP packet. + * Find the peer associated with an ICMPv4 packet. */ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, - const struct sk_buff *skb, + struct sk_buff *skb, + unsigned int udp_offset, + unsigned int *info, struct sockaddr_rxrpc *srx) { - struct sock_exterr_skb *serr = SKB_EXT_ERR(skb); + struct iphdr *ip, *ip0 = ip_hdr(skb); + struct icmphdr *icmp = icmp_hdr(skb); + struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset); - _enter(""); + _enter("%u,%u,%u", ip0->protocol, icmp->type, icmp->code); + + switch (icmp->type) { + case ICMP_DEST_UNREACH: + *info = ntohs(icmp->un.frag.mtu); + fallthrough; + case ICMP_TIME_EXCEEDED: + case ICMP_PARAMETERPROB: + ip = (struct iphdr *)((void *)icmp + 8); + break; + default: + return NULL; + } + + memset(srx, 0, sizeof(*srx)); + srx->transport_type = local->srx.transport_type; + srx->transport_len = local->srx.transport_len; + srx->transport.family = local->srx.transport.family; + + /* Can we see an ICMP4 packet on an ICMP6 listening socket? and vice + * versa? + */ + switch (srx->transport.family) { + case AF_INET: + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, &ip->daddr, + sizeof(struct in_addr)); + break; + +#ifdef CONFIG_AF_RXRPC_IPV6 + case AF_INET6: + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, &ip->daddr, + sizeof(struct in_addr)); + break; +#endif + + default: + WARN_ON_ONCE(1); + return NULL; + } + + _net("ICMP {%pISp}", &srx->transport); + return rxrpc_lookup_peer_rcu(local, srx); +} + +#ifdef CONFIG_AF_RXRPC_IPV6 +/* + * Find the peer associated with an ICMPv6 packet. + */ +static struct rxrpc_peer *rxrpc_lookup_peer_icmp6_rcu(struct rxrpc_local *local, + struct sk_buff *skb, + unsigned int udp_offset, + unsigned int *info, + struct sockaddr_rxrpc *srx) +{ + struct icmp6hdr *icmp = icmp6_hdr(skb); + struct ipv6hdr *ip, *ip0 = ipv6_hdr(skb); + struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset); + + _enter("%u,%u,%u", ip0->nexthdr, icmp->icmp6_type, icmp->icmp6_code); + + switch (icmp->icmp6_type) { + case ICMPV6_DEST_UNREACH: + *info = ntohl(icmp->icmp6_mtu); + fallthrough; + case ICMPV6_PKT_TOOBIG: + case ICMPV6_TIME_EXCEED: + case ICMPV6_PARAMPROB: + ip = (struct ipv6hdr *)((void *)icmp + 8); + break; + default: + return NULL; + } memset(srx, 0, sizeof(*srx)); srx->transport_type = local->srx.transport_type; @@ -41,6 +124,165 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, /* Can we see an ICMP4 packet on an ICMP6 listening socket? and vice * versa? */ + switch (srx->transport.family) { + case AF_INET: + _net("Rx ICMP6 on v4 sock"); + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, + &ip->daddr.s6_addr32[3], sizeof(struct in_addr)); + break; + case AF_INET6: + _net("Rx ICMP6"); + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin6.sin6_addr, &ip->daddr, + sizeof(struct in6_addr)); + break; + default: + WARN_ON_ONCE(1); + return NULL; + } + + _net("ICMP {%pISp}", &srx->transport); + return rxrpc_lookup_peer_rcu(local, srx); +} +#endif /* CONFIG_AF_RXRPC_IPV6 */ + +/* + * Handle an error received on the local endpoint as a tunnel. + */ +void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, + unsigned int udp_offset) +{ + struct sock_extended_err ee; + struct sockaddr_rxrpc srx; + struct rxrpc_local *local; + struct rxrpc_peer *peer; + unsigned int info = 0; + int err; + u8 version = ip_hdr(skb)->version; + u8 type = icmp_hdr(skb)->type; + u8 code = icmp_hdr(skb)->code; + + rcu_read_lock(); + local = rcu_dereference_sk_user_data(sk); + if (unlikely(!local)) { + rcu_read_unlock(); + return; + } + + rxrpc_new_skb(skb, rxrpc_skb_received); + + switch (ip_hdr(skb)->version) { + case IPVERSION: + peer = rxrpc_lookup_peer_icmp_rcu(local, skb, udp_offset, + &info, &srx); + break; +#ifdef CONFIG_AF_RXRPC_IPV6 + case 6: + peer = rxrpc_lookup_peer_icmp6_rcu(local, skb, udp_offset, + &info, &srx); + break; +#endif + default: + rcu_read_unlock(); + return; + } + + if (peer && !rxrpc_get_peer_maybe(peer)) + peer = NULL; + if (!peer) { + rcu_read_unlock(); + return; + } + + memset(&ee, 0, sizeof(ee)); + + switch (version) { + case IPVERSION: + switch (type) { + case ICMP_DEST_UNREACH: + switch (code) { + case ICMP_FRAG_NEEDED: + rxrpc_adjust_mtu(peer, info); + rcu_read_unlock(); + rxrpc_put_peer(peer); + return; + default: + break; + } + + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + /* Might want to do something different with + * non-fatal errors + */ + //harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + default: + err = EPROTO; + break; + } + + ee.ee_origin = SO_EE_ORIGIN_ICMP; + ee.ee_type = type; + ee.ee_code = code; + ee.ee_errno = err; + break; + +#ifdef CONFIG_AF_RXRPC_IPV6 + case 6: + switch (type) { + case ICMPV6_PKT_TOOBIG: + rxrpc_adjust_mtu(peer, info); + rcu_read_unlock(); + rxrpc_put_peer(peer); + return; + } + + icmpv6_err_convert(type, code, &err); + + if (err == EACCES) + err = EHOSTUNREACH; + + ee.ee_origin = SO_EE_ORIGIN_ICMP6; + ee.ee_type = type; + ee.ee_code = code; + ee.ee_errno = err; + break; +#endif + } + + trace_rxrpc_rx_icmp(peer, &ee, &srx); + + rxrpc_distribute_error(peer, err, RXRPC_CALL_NETWORK_ERROR); + rcu_read_unlock(); + rxrpc_put_peer(peer); +} + +/* + * Find the peer associated with a local error. + */ +static struct rxrpc_peer *rxrpc_lookup_peer_local_rcu(struct rxrpc_local *local, + const struct sk_buff *skb, + struct sockaddr_rxrpc *srx) +{ + struct sock_exterr_skb *serr = SKB_EXT_ERR(skb); + + _enter(""); + + memset(srx, 0, sizeof(*srx)); + srx->transport_type = local->srx.transport_type; + srx->transport_len = local->srx.transport_len; + srx->transport.family = local->srx.transport.family; + switch (srx->transport.family) { case AF_INET: srx->transport_len = sizeof(srx->transport.sin); @@ -104,10 +346,8 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, /* * Handle an MTU/fragmentation problem. */ -static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, struct sock_exterr_skb *serr) +static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, unsigned int mtu) { - u32 mtu = serr->ee.ee_info; - _net("Rx ICMP Fragmentation Needed (%d)", mtu); /* wind down the local interface MTU */ @@ -148,7 +388,7 @@ void rxrpc_error_report(struct sock *sk) struct sock_exterr_skb *serr; struct sockaddr_rxrpc srx; struct rxrpc_local *local; - struct rxrpc_peer *peer; + struct rxrpc_peer *peer = NULL; struct sk_buff *skb; rcu_read_lock(); @@ -172,41 +412,20 @@ void rxrpc_error_report(struct sock *sk) } rxrpc_new_skb(skb, rxrpc_skb_received); serr = SKB_EXT_ERR(skb); - if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { - _leave("UDP empty message"); - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - return; - } - peer = rxrpc_lookup_peer_icmp_rcu(local, skb, &srx); - if (peer && !rxrpc_get_peer_maybe(peer)) - peer = NULL; - if (!peer) { - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - _leave(" [no peer]"); - return; - } - - trace_rxrpc_rx_icmp(peer, &serr->ee, &srx); - - if ((serr->ee.ee_origin == SO_EE_ORIGIN_ICMP && - serr->ee.ee_type == ICMP_DEST_UNREACH && - serr->ee.ee_code == ICMP_FRAG_NEEDED)) { - rxrpc_adjust_mtu(peer, serr); - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - rxrpc_put_peer(peer); - _leave(" [MTU update]"); - return; + if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL) { + peer = rxrpc_lookup_peer_local_rcu(local, skb, &srx); + if (peer && !rxrpc_get_peer_maybe(peer)) + peer = NULL; + if (peer) { + trace_rxrpc_rx_icmp(peer, &serr->ee, &srx); + rxrpc_store_error(peer, serr); + } } - rxrpc_store_error(peer, serr); rcu_read_unlock(); rxrpc_free_skb(skb, rxrpc_skb_freed); rxrpc_put_peer(peer); - _leave(""); } From e28eb3519d5ff88bce929d9c7d349242a40bdbb2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Aug 2022 22:39:28 +0100 Subject: [PATCH 181/228] rxrpc: Fix an insufficiently large sglist in rxkad_verify_packet_2() [ Upstream commit 0d40f728e28393a8817d1fcae923dfa3409e488c ] rxkad_verify_packet_2() has a small stack-allocated sglist of 4 elements, but if that isn't sufficient for the number of fragments in the socket buffer, we try to allocate an sglist large enough to hold all the fragments. However, for large packets with a lot of fragments, this isn't sufficient and we need at least one additional fragment. The problem manifests as skb_to_sgvec() returning -EMSGSIZE and this then getting returned by userspace. Most of the time, this isn't a problem as rxrpc sets a limit of 5692, big enough for 4 jumbo subpackets to be glued together; occasionally, however, the server will ignore the reported limit and give a packet that's a lot bigger - say 19852 bytes with ->nr_frags being 7. skb_to_sgvec() then tries to return a "zeroth" fragment that seems to occur before the fragments counted by ->nr_frags and we hit the end of the sglist too early. Note that __skb_to_sgvec() also has an skb_walk_frags() loop that is recursive up to 24 deep. I'm not sure if I need to take account of that too - or if there's an easy way of counting those frags too. Fix this by counting an extra frag and allocating a larger sglist based on that. Fixes: d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()") Reported-by: Marc Dionne Signed-off-by: David Howells cc: linux-afs@lists.infradead.org Signed-off-by: Sasha Levin --- net/rxrpc/rxkad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 08aab5c01437d..db47844f4ac99 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -540,7 +540,7 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, * directly into the target buffer. */ sg = _sg; - nsg = skb_shinfo(skb)->nr_frags; + nsg = skb_shinfo(skb)->nr_frags + 1; if (nsg <= 4) { nsg = 4; } else { From 2f6640b19edffed651a08419fe1a9d858df411b1 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 Aug 2022 13:16:42 +0100 Subject: [PATCH 182/228] afs: Use the operation issue time instead of the reply time for callbacks [ Upstream commit 7903192c4b4a82d792cb0dc5e2779a2efe60d45b ] rxrpc and kafs between them try to use the receive timestamp on the first data packet (ie. the one with sequence number 1) as a base from which to calculate the time at which callback promise and lock expiration occurs. However, we don't know how long it took for the server to send us the reply from it having completed the basic part of the operation - it might then, for instance, have to send a bunch of a callback breaks, depending on the particular operation. Fix this by using the time at which the operation is issued on the client as a base instead. That should never be longer than the server's idea of the expiry time. Fixes: 781070551c26 ("afs: Fix calculation of callback expiry time") Fixes: 2070a3e44962 ("rxrpc: Allow the reply time to be obtained on a client call") Suggested-by: Jeffrey E Altman Signed-off-by: David Howells Signed-off-by: Sasha Levin --- fs/afs/flock.c | 2 +- fs/afs/fsclient.c | 2 +- fs/afs/internal.h | 3 +-- fs/afs/rxrpc.c | 7 +------ fs/afs/yfsclient.c | 3 +-- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/fs/afs/flock.c b/fs/afs/flock.c index c4210a3964d8b..bbcc5afd15760 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -76,7 +76,7 @@ void afs_lock_op_done(struct afs_call *call) if (call->error == 0) { spin_lock(&vnode->lock); trace_afs_flock_ev(vnode, NULL, afs_flock_timestamp, 0); - vnode->locked_at = call->reply_time; + vnode->locked_at = call->issue_time; afs_schedule_lock_extension(vnode); spin_unlock(&vnode->lock); } diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 4943413d9c5f7..7d37f63ef0f09 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -131,7 +131,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry) { - return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry; + return ktime_divns(call->issue_time, NSEC_PER_SEC) + expiry; } static void xdr_decode_AFSCallBack(const __be32 **_bp, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 0ad97a8fc0d49..567e61b553f56 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -138,7 +138,6 @@ struct afs_call { bool need_attention; /* T if RxRPC poked us */ bool async; /* T if asynchronous */ bool upgrade; /* T to request service upgrade */ - bool have_reply_time; /* T if have got reply_time */ bool intr; /* T if interruptible */ bool unmarshalling_error; /* T if an unmarshalling error occurred */ u16 service_id; /* Actual service ID (after upgrade) */ @@ -152,7 +151,7 @@ struct afs_call { } __attribute__((packed)); __be64 tmp64; }; - ktime_t reply_time; /* Time of first reply packet */ + ktime_t issue_time; /* Time of issue of operation */ }; struct afs_call_type { diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index a5434f3e57c68..e3de7fea36435 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -347,6 +347,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) if (call->max_lifespan) rxrpc_kernel_set_max_life(call->net->socket, rxcall, call->max_lifespan); + call->issue_time = ktime_get_real(); /* send the request */ iov[0].iov_base = call->request; @@ -497,12 +498,6 @@ static void afs_deliver_to_call(struct afs_call *call) return; } - if (!call->have_reply_time && - rxrpc_kernel_get_reply_time(call->net->socket, - call->rxcall, - &call->reply_time)) - call->have_reply_time = true; - ret = call->type->deliver(call); state = READ_ONCE(call->state); if (ret == 0 && call->unmarshalling_error) diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 2b35cba8ad62b..88ea20e79ae27 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -239,8 +239,7 @@ static void xdr_decode_YFSCallBack(const __be32 **_bp, struct afs_callback *cb = &scb->callback; ktime_t cb_expiry; - cb_expiry = call->reply_time; - cb_expiry = ktime_add(cb_expiry, xdr_to_u64(x->expiration_time) * 100); + cb_expiry = ktime_add(call->issue_time, xdr_to_u64(x->expiration_time) * 100); cb->expires_at = ktime_divns(cb_expiry, NSEC_PER_SEC); scb->have_cb = true; *_bp += xdr_size(x); From b0b35b455eced3beb3564cf376aafd6fb1eb5b2f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 31 Aug 2022 21:20:49 +0200 Subject: [PATCH 183/228] Revert "net: phy: meson-gxl: improve link-up behavior" [ Upstream commit 7fdc77665f3d45c9da7c6edd4beadee9790f43aa ] This reverts commit 2c87c6f9fbddc5b84d67b2fa3f432fcac6d99d93. Meanwhile it turned out that the following commit is the proper workaround for the issue that 2c87c6f9fbdd tries to address. a3a57bf07de2 ("net: stmmac: work around sporadic tx issue on link-up") It's nor clear why the to be reverted commit helped for one user, for others it didn't make a difference. Fixes: 2c87c6f9fbdd ("net: phy: meson-gxl: improve link-up behavior") Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/8deeeddc-6b71-129b-1918-495a12dc11e3@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/meson-gxl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index 73f7962a37d33..c49062ad72c6c 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -243,13 +243,7 @@ static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev) irq_status == INTSRC_ENERGY_DETECT) return IRQ_HANDLED; - /* Give PHY some time before MAC starts sending data. This works - * around an issue where network doesn't come up properly. - */ - if (!(irq_status & INTSRC_LINK_DOWN)) - phy_queue_state_machine(phydev, msecs_to_jiffies(100)); - else - phy_trigger_machine(phydev); + phy_trigger_machine(phydev); return IRQ_HANDLED; } From 1a889da60afc017050e1f517b3b976b462846668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Wed, 31 Aug 2022 23:52:18 +0200 Subject: [PATCH 184/228] sch_sfb: Don't assume the skb is still around after enqueueing to child MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9efd23297cca530bb35e1848665805d3fcdd7889 ] The sch_sfb enqueue() routine assumes the skb is still alive after it has been enqueued into a child qdisc, using the data in the skb cb field in the increment_qlen() routine after enqueue. However, the skb may in fact have been freed, causing a use-after-free in this case. In particular, this happens if sch_cake is used as a child of sfb, and the GSO splitting mode of CAKE is enabled (in which case the skb will be split into segments and the original skb freed). Fix this by copying the sfb cb data to the stack before enqueueing the skb, and using this stack copy in increment_qlen() instead of the skb pointer itself. Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-18231 Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler") Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/sch_sfb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 3d061a13d7ed2..0d761f454ae8b 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -135,15 +135,15 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) } } -static void increment_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) +static void increment_qlen(const struct sfb_skb_cb *cb, struct sfb_sched_data *q) { u32 sfbhash; - sfbhash = sfb_hash(skb, 0); + sfbhash = cb->hashes[0]; if (sfbhash) increment_one_qlen(sfbhash, 0, q); - sfbhash = sfb_hash(skb, 1); + sfbhash = cb->hashes[1]; if (sfbhash) increment_one_qlen(sfbhash, 1, q); } @@ -283,6 +283,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sfb_sched_data *q = qdisc_priv(sch); struct Qdisc *child = q->qdisc; struct tcf_proto *fl; + struct sfb_skb_cb cb; int i; u32 p_min = ~0; u32 minqlen = ~0; @@ -399,11 +400,12 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, } enqueue: + memcpy(&cb, sfb_skb_cb(skb), sizeof(cb)); ret = qdisc_enqueue(skb, child, to_free); if (likely(ret == NET_XMIT_SUCCESS)) { qdisc_qstats_backlog_inc(sch, skb); sch->q.qlen++; - increment_qlen(skb, q); + increment_qlen(&cb, q); } else if (net_xmit_drop_count(ret)) { q->stats.childdrop++; qdisc_qstats_drop(sch); From 7eb9bf4edd1c7d65fe59e4d4a27b33ba8dd00098 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 31 Aug 2022 17:47:56 +0300 Subject: [PATCH 185/228] tipc: fix shift wrapping bug in map_get() [ Upstream commit e2b224abd9bf45dcb55750479fc35970725a430b ] There is a shift wrapping bug in this code so anything thing above 31 will return false. Fixes: 35c55c9877f8 ("tipc: add neighbor monitoring framework") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/tipc/monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index 2f4d23238a7e3..9618e4429f0fe 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -160,7 +160,7 @@ static void map_set(u64 *up_map, int i, unsigned int v) static int map_get(u64 up_map, int i) { - return (up_map & (1 << i)) >> i; + return (up_map & (1ULL << i)) >> i; } static struct tipc_peer *peer_prev(struct tipc_peer *peer) From cd5f1a69d0b603bd673994c8a0676f9d3aa0f2b1 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Tue, 12 Jul 2022 21:52:32 +0100 Subject: [PATCH 186/228] net: introduce __skb_fill_page_desc_noacc [ Upstream commit 84ce071e38a6e25ea3ea91188e5482ac1f17b3af ] Managed pages contain pinned userspace pages and controlled by upper layers, there is no need in tracking skb->pfmemalloc for them. Introduce a helper for filling frags but ignoring page tracking, it'll be needed later. Signed-off-by: Pavel Begunkov Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/linux/skbuff.h | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ae598ed86b50b..be7cc31d58961 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2232,6 +2232,22 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb) return skb_headlen(skb) + __skb_pagelen(skb); } +static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo, + int i, struct page *page, + int off, int size) +{ + skb_frag_t *frag = &shinfo->frags[i]; + + /* + * Propagate page pfmemalloc to the skb if we can. The problem is + * that not all callers have unique ownership of the page but rely + * on page_is_pfmemalloc doing the right thing(tm). + */ + frag->bv_page = page; + frag->bv_offset = off; + skb_frag_size_set(frag, size); +} + /** * __skb_fill_page_desc - initialise a paged fragment in an skb * @skb: buffer containing fragment to be initialised @@ -2248,17 +2264,7 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb) static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - /* - * Propagate page pfmemalloc to the skb if we can. The problem is - * that not all callers have unique ownership of the page but rely - * on page_is_pfmemalloc doing the right thing(tm). - */ - frag->bv_page = page; - frag->bv_offset = off; - skb_frag_size_set(frag, size); - + __skb_fill_page_desc_noacc(skb_shinfo(skb), i, page, off, size); page = compound_head(page); if (page_is_pfmemalloc(page)) skb->pfmemalloc = true; From 8527c9a6bf8e54fef0a8d3d7d8874a48c725c915 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 31 Aug 2022 23:38:09 +0000 Subject: [PATCH 187/228] tcp: TX zerocopy should not sense pfmemalloc status [ Upstream commit 3261400639463a853ba2b3be8bd009c2a8089775 ] We got a recent syzbot report [1] showing a possible misuse of pfmemalloc page status in TCP zerocopy paths. Indeed, for pages coming from user space or other layers, using page_is_pfmemalloc() is moot, and possibly could give false positives. There has been attempts to make page_is_pfmemalloc() more robust, but not using it in the first place in this context is probably better, removing cpu cycles. Note to stable teams : You need to backport 84ce071e38a6 ("net: introduce __skb_fill_page_desc_noacc") as a prereq. Race is more probable after commit c07aea3ef4d4 ("mm: add a signature in struct page") because page_is_pfmemalloc() is now using low order bit from page->lru.next, which can change more often than page->index. Low order bit should never be set for lru.next (when used as an anchor in LRU list), so KCSAN report is mostly a false positive. Backporting to older kernel versions seems not necessary. [1] BUG: KCSAN: data-race in lru_add_fn / tcp_build_frag write to 0xffffea0004a1d2c8 of 8 bytes by task 18600 on cpu 0: __list_add include/linux/list.h:73 [inline] list_add include/linux/list.h:88 [inline] lruvec_add_folio include/linux/mm_inline.h:105 [inline] lru_add_fn+0x440/0x520 mm/swap.c:228 folio_batch_move_lru+0x1e1/0x2a0 mm/swap.c:246 folio_batch_add_and_move mm/swap.c:263 [inline] folio_add_lru+0xf1/0x140 mm/swap.c:490 filemap_add_folio+0xf8/0x150 mm/filemap.c:948 __filemap_get_folio+0x510/0x6d0 mm/filemap.c:1981 pagecache_get_page+0x26/0x190 mm/folio-compat.c:104 grab_cache_page_write_begin+0x2a/0x30 mm/folio-compat.c:116 ext4_da_write_begin+0x2dd/0x5f0 fs/ext4/inode.c:2988 generic_perform_write+0x1d4/0x3f0 mm/filemap.c:3738 ext4_buffered_write_iter+0x235/0x3e0 fs/ext4/file.c:270 ext4_file_write_iter+0x2e3/0x1210 call_write_iter include/linux/fs.h:2187 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x468/0x760 fs/read_write.c:578 ksys_write+0xe8/0x1a0 fs/read_write.c:631 __do_sys_write fs/read_write.c:643 [inline] __se_sys_write fs/read_write.c:640 [inline] __x64_sys_write+0x3e/0x50 fs/read_write.c:640 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x2b/0x70 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd read to 0xffffea0004a1d2c8 of 8 bytes by task 18611 on cpu 1: page_is_pfmemalloc include/linux/mm.h:1740 [inline] __skb_fill_page_desc include/linux/skbuff.h:2422 [inline] skb_fill_page_desc include/linux/skbuff.h:2443 [inline] tcp_build_frag+0x613/0xb20 net/ipv4/tcp.c:1018 do_tcp_sendpages+0x3e8/0xaf0 net/ipv4/tcp.c:1075 tcp_sendpage_locked net/ipv4/tcp.c:1140 [inline] tcp_sendpage+0x89/0xb0 net/ipv4/tcp.c:1150 inet_sendpage+0x7f/0xc0 net/ipv4/af_inet.c:833 kernel_sendpage+0x184/0x300 net/socket.c:3561 sock_sendpage+0x5a/0x70 net/socket.c:1054 pipe_to_sendpage+0x128/0x160 fs/splice.c:361 splice_from_pipe_feed fs/splice.c:415 [inline] __splice_from_pipe+0x222/0x4d0 fs/splice.c:559 splice_from_pipe fs/splice.c:594 [inline] generic_splice_sendpage+0x89/0xc0 fs/splice.c:743 do_splice_from fs/splice.c:764 [inline] direct_splice_actor+0x80/0xa0 fs/splice.c:931 splice_direct_to_actor+0x305/0x620 fs/splice.c:886 do_splice_direct+0xfb/0x180 fs/splice.c:974 do_sendfile+0x3bf/0x910 fs/read_write.c:1249 __do_sys_sendfile64 fs/read_write.c:1317 [inline] __se_sys_sendfile64 fs/read_write.c:1303 [inline] __x64_sys_sendfile64+0x10c/0x150 fs/read_write.c:1303 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x2b/0x70 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd value changed: 0x0000000000000000 -> 0xffffea0004a1d288 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 18611 Comm: syz-executor.4 Not tainted 6.0.0-rc2-syzkaller-00248-ge022620b5d05-dirty #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/22/2022 Fixes: c07aea3ef4d4 ("mm: add a signature in struct page") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Shakeel Butt Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- include/linux/skbuff.h | 21 +++++++++++++++++++++ net/core/datagram.c | 2 +- net/ipv4/tcp.c | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index be7cc31d58961..cfb889f66c703 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2291,6 +2291,27 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i, skb_shinfo(skb)->nr_frags = i + 1; } +/** + * skb_fill_page_desc_noacc - initialise a paged fragment in an skb + * @skb: buffer containing fragment to be initialised + * @i: paged fragment index to initialise + * @page: the page to use for this fragment + * @off: the offset to the data with @page + * @size: the length of the data + * + * Variant of skb_fill_page_desc() which does not deal with + * pfmemalloc, if page is not owned by us. + */ +static inline void skb_fill_page_desc_noacc(struct sk_buff *skb, int i, + struct page *page, int off, + int size) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + + __skb_fill_page_desc_noacc(shinfo, i, page, off, size); + shinfo->nr_frags = i + 1; +} + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, int size, unsigned int truesize); diff --git a/net/core/datagram.c b/net/core/datagram.c index 15ab9ffb27fe9..28e5f921dcaf4 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -677,7 +677,7 @@ int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb, page_ref_sub(last_head, refs); refs = 0; } - skb_fill_page_desc(skb, frag++, head, start, size); + skb_fill_page_desc_noacc(skb, frag++, head, start, size); } if (refs) page_ref_sub(last_head, refs); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0ebef2a5950cd..4f6b897ccf23f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1002,7 +1002,7 @@ struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags, skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); } else { get_page(page); - skb_fill_page_desc(skb, i, page, offset, copy); + skb_fill_page_desc_noacc(skb, i, page, offset, copy); } if (!(flags & MSG_NO_SHARED_FRAGS)) From 3e245b0e21685e4bff4f930f9127313da70b67e6 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Wed, 17 Aug 2022 10:53:20 +0200 Subject: [PATCH 188/228] ice: use bitmap_free instead of devm_kfree [ Upstream commit 59ac325557b6c14f1f793b90d3946bc145ffa085 ] pf->avail_txqs was allocated using bitmap_zalloc, bitmap_free should be used to free this memory. Fixes: 78b5713ac1241 ("ice: Alloc queue management bitmaps and arrays dynamically") Signed-off-by: Michal Swiatkowski Tested-by: Gurucharan (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b9d45c7dbef18..63ae4674d2000 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3549,7 +3549,7 @@ static int ice_init_pf(struct ice_pf *pf) pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL); if (!pf->avail_rxqs) { - devm_kfree(ice_pf_to_dev(pf), pf->avail_txqs); + bitmap_free(pf->avail_txqs); pf->avail_txqs = NULL; return -ENOMEM; } From 2ed94383f3a2693dbf5bc47c514b42524bd8f9ae Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 16 Aug 2022 18:22:30 +0200 Subject: [PATCH 189/228] i40e: Fix kernel crash during module removal [ Upstream commit fb8396aeda5872369a8ed6d2301e2c86e303c520 ] The driver incorrectly frees client instance and subsequent i40e module removal leads to kernel crash. Reproducer: 1. Do ethtool offline test followed immediately by another one host# ethtool -t eth0 offline; ethtool -t eth0 offline 2. Remove recursively irdma module that also removes i40e module host# modprobe -r irdma Result: [ 8675.035651] i40e 0000:3d:00.0 eno1: offline testing starting [ 8675.193774] i40e 0000:3d:00.0 eno1: testing finished [ 8675.201316] i40e 0000:3d:00.0 eno1: offline testing starting [ 8675.358921] i40e 0000:3d:00.0 eno1: testing finished [ 8675.496921] i40e 0000:3d:00.0: IRDMA hardware initialization FAILED init_state=2 status=-110 [ 8686.188955] i40e 0000:3d:00.1: i40e_ptp_stop: removed PHC on eno2 [ 8686.943890] i40e 0000:3d:00.1: Deleted LAN device PF1 bus=0x3d dev=0x00 func=0x01 [ 8686.952669] i40e 0000:3d:00.0: i40e_ptp_stop: removed PHC on eno1 [ 8687.761787] BUG: kernel NULL pointer dereference, address: 0000000000000030 [ 8687.768755] #PF: supervisor read access in kernel mode [ 8687.773895] #PF: error_code(0x0000) - not-present page [ 8687.779034] PGD 0 P4D 0 [ 8687.781575] Oops: 0000 [#1] PREEMPT SMP NOPTI [ 8687.785935] CPU: 51 PID: 172891 Comm: rmmod Kdump: loaded Tainted: G W I 5.19.0+ #2 [ 8687.794800] Hardware name: Intel Corporation S2600WFD/S2600WFD, BIOS SE5C620.86B.0X.02.0001.051420190324 05/14/2019 [ 8687.805222] RIP: 0010:i40e_lan_del_device+0x13/0xb0 [i40e] [ 8687.810719] Code: d4 84 c0 0f 84 b8 25 01 00 e9 9c 25 01 00 41 bc f4 ff ff ff eb 91 90 0f 1f 44 00 00 41 54 55 53 48 8b 87 58 08 00 00 48 89 fb <48> 8b 68 30 48 89 ef e8 21 8a 0f d5 48 89 ef e8 a9 78 0f d5 48 8b [ 8687.829462] RSP: 0018:ffffa604072efce0 EFLAGS: 00010202 [ 8687.834689] RAX: 0000000000000000 RBX: ffff8f43833b2000 RCX: 0000000000000000 [ 8687.841821] RDX: 0000000000000000 RSI: ffff8f4b0545b298 RDI: ffff8f43833b2000 [ 8687.848955] RBP: ffff8f43833b2000 R08: 0000000000000001 R09: 0000000000000000 [ 8687.856086] R10: 0000000000000000 R11: 000ffffffffff000 R12: ffff8f43833b2ef0 [ 8687.863218] R13: ffff8f43833b2ef0 R14: ffff915103966000 R15: ffff8f43833b2008 [ 8687.870342] FS: 00007f79501c3740(0000) GS:ffff8f4adffc0000(0000) knlGS:0000000000000000 [ 8687.878427] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 8687.884174] CR2: 0000000000000030 CR3: 000000014276e004 CR4: 00000000007706e0 [ 8687.891306] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 8687.898441] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 8687.905572] PKRU: 55555554 [ 8687.908286] Call Trace: [ 8687.910737] [ 8687.912843] i40e_remove+0x2c0/0x330 [i40e] [ 8687.917040] pci_device_remove+0x33/0xa0 [ 8687.920962] device_release_driver_internal+0x1aa/0x230 [ 8687.926188] driver_detach+0x44/0x90 [ 8687.929770] bus_remove_driver+0x55/0xe0 [ 8687.933693] pci_unregister_driver+0x2a/0xb0 [ 8687.937967] i40e_exit_module+0xc/0xf48 [i40e] Two offline tests cause IRDMA driver failure (ETIMEDOUT) and this failure is indicated back to i40e_client_subtask() that calls i40e_client_del_instance() to free client instance referenced by pf->cinst and sets this pointer to NULL. During the module removal i40e_remove() calls i40e_lan_del_device() that dereferences pf->cinst that is NULL -> crash. Do not remove client instance when client open callbacks fails and just clear __I40E_CLIENT_INSTANCE_OPENED bit. The driver also needs to take care about this situation (when netdev is up and client is NOT opened) in i40e_notify_client_of_netdev_close() and calls client close callback only when __I40E_CLIENT_INSTANCE_OPENED is set. Fixes: 0ef2d5afb12d ("i40e: KISS the client interface") Signed-off-by: Ivan Vecera Tested-by: Helena Anna Dubel Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/i40e/i40e_client.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index ea2bb0140a6eb..10d7a982a5b9b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -177,6 +177,10 @@ void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset) "Cannot locate client instance close routine\n"); return; } + if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) { + dev_dbg(&pf->pdev->dev, "Client is not open, abort close\n"); + return; + } cdev->client->ops->close(&cdev->lan_info, cdev->client, reset); clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state); i40e_client_release_qvlist(&cdev->lan_info); @@ -429,7 +433,6 @@ void i40e_client_subtask(struct i40e_pf *pf) /* Remove failed client instance */ clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state); - i40e_client_del_instance(pf); return; } } From c3efe896f13b83b227d8a4637c81e108d1a6795f Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 30 Aug 2022 10:16:27 +0200 Subject: [PATCH 190/228] iavf: Detach device during reset task [ Upstream commit aa626da947e9cd30c4cf727493903e1adbb2c0a0 ] iavf_reset_task() takes crit_lock at the beginning and holds it during whole call. The function subsequently calls iavf_init_interrupt_scheme() that grabs RTNL. Problem occurs when userspace initiates during the reset task any ndo callback that runs under RTNL like iavf_open() because some of that functions tries to take crit_lock. This leads to classic A-B B-A deadlock scenario. To resolve this situation the device should be detached in iavf_reset_task() prior taking crit_lock to avoid subsequent ndos running under RTNL and reattach the device at the end. Fixes: 62fe2a865e6d ("i40evf: add missing rtnl_lock() around i40evf_set_interrupt_capability") Cc: Jacob Keller Cc: Patryk Piotrowski Cc: SlawomirX Laba Tested-by: Vitaly Grinberg Signed-off-by: Ivan Vecera Tested-by: Konrad Jankowski Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/iavf/iavf_main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index db95786c3419f..00b2ef01f4ea6 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -2222,6 +2222,11 @@ static void iavf_reset_task(struct work_struct *work) int i = 0, err; bool running; + /* Detach interface to avoid subsequent NDO callbacks */ + rtnl_lock(); + netif_device_detach(netdev); + rtnl_unlock(); + /* When device is being removed it doesn't make sense to run the reset * task, just return in such a case. */ @@ -2229,7 +2234,7 @@ static void iavf_reset_task(struct work_struct *work) if (adapter->state != __IAVF_REMOVE) queue_work(iavf_wq, &adapter->reset_task); - return; + goto reset_finish; } while (!mutex_trylock(&adapter->client_lock)) @@ -2299,7 +2304,6 @@ static void iavf_reset_task(struct work_struct *work) if (running) { netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); adapter->link_up = false; iavf_napi_disable_all(adapter); } @@ -2412,7 +2416,7 @@ static void iavf_reset_task(struct work_struct *work) mutex_unlock(&adapter->client_lock); mutex_unlock(&adapter->crit_lock); - return; + goto reset_finish; reset_err: if (running) { set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); @@ -2423,6 +2427,10 @@ static void iavf_reset_task(struct work_struct *work) mutex_unlock(&adapter->client_lock); mutex_unlock(&adapter->crit_lock); dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); +reset_finish: + rtnl_lock(); + netif_device_attach(netdev); + rtnl_unlock(); } /** From 595e3616f8e0be5d6ef3f70e9966191c091ef691 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Thu, 1 Sep 2022 12:55:54 +0100 Subject: [PATCH 191/228] xen-netback: only remove 'hotplug-status' when the vif is actually destroyed [ Upstream commit c55f34b6aec2a8cb47eadaffea773e83bf85de91 ] Removing 'hotplug-status' in backend_disconnected() means that it will be removed even in the case that the frontend unilaterally disconnects (which it is free to do at any time). The consequence of this is that, when the frontend attempts to re-connect, the backend gets stuck in 'InitWait' rather than moving straight to 'Connected' (which it can do because the hotplug script has already run). Instead, the 'hotplug-status' mode should be removed in netback_remove() i.e. when the vif really is going away. Fixes: 0f4558ae9187 ("Revert "xen-netback: remove 'hotplug-status' once it has served its purpose"") Signed-off-by: Paul Durrant Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/xen-netback/xenbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 990360d75cb64..e85b3c5d4acce 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -256,7 +256,6 @@ static void backend_disconnect(struct backend_info *be) unsigned int queue_index; xen_unregister_watchers(vif); - xenbus_rm(XBT_NIL, be->dev->nodename, "hotplug-status"); #ifdef CONFIG_DEBUG_FS xenvif_debugfs_delif(vif); #endif /* CONFIG_DEBUG_FS */ @@ -984,6 +983,7 @@ static int netback_remove(struct xenbus_device *dev) struct backend_info *be = dev_get_drvdata(&dev->dev); unregister_hotplug_status_watch(be); + xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); if (be->vif) { kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); backend_disconnect(be); From 4c4eda13641017577e3b7e1d6d23cfd11a56e003 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 2 Sep 2022 23:59:18 +0200 Subject: [PATCH 192/228] RDMA/siw: Pass a pointer to virt_to_page() [ Upstream commit 0d1b756acf60da5004c1e20ca4462f0c257bf6e1 ] Functions that work on a pointer to virtual memory such as virt_to_pfn() and users of that function such as virt_to_page() are supposed to pass a pointer to virtual memory, ideally a (void *) or other pointer. However since many architectures implement virt_to_pfn() as a macro, this function becomes polymorphic and accepts both a (unsigned long) and a (void *). If we instead implement a proper virt_to_pfn(void *addr) function the following happens (occurred on arch/arm): drivers/infiniband/sw/siw/siw_qp_tx.c:32:23: warning: incompatible integer to pointer conversion passing 'dma_addr_t' (aka 'unsigned int') to parameter of type 'const void *' [-Wint-conversion] drivers/infiniband/sw/siw/siw_qp_tx.c:32:37: warning: passing argument 1 of 'virt_to_pfn' makes pointer from integer without a cast [-Wint-conversion] drivers/infiniband/sw/siw/siw_qp_tx.c:538:36: warning: incompatible integer to pointer conversion passing 'unsigned long long' to parameter of type 'const void *' [-Wint-conversion] Fix this with an explicit cast. In one case where the SIW SGE uses an unaligned u64 we need a double cast modifying the virtual address (va) to a platform-specific uintptr_t before casting to a (void *). Fixes: b9be6f18cf9e ("rdma/siw: transmit path") Cc: linux-rdma@vger.kernel.org Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220902215918.603761-1-linus.walleij@linaro.org Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/sw/siw/siw_qp_tx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 1f4e60257700e..7d47b521070b1 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -29,7 +29,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx) dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx); if (paddr) - return virt_to_page(paddr); + return virt_to_page((void *)paddr); return NULL; } @@ -533,13 +533,23 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s) kunmap_local(kaddr); } } else { - u64 va = sge->laddr + sge_off; + /* + * Cast to an uintptr_t to preserve all 64 bits + * in sge->laddr. + */ + uintptr_t va = (uintptr_t)(sge->laddr + sge_off); - page_array[seg] = virt_to_page(va & PAGE_MASK); + /* + * virt_to_page() takes a (void *) pointer + * so cast to a (void *) meaning it will be 64 + * bits on a 64 bit platform and 32 bits on a + * 32 bit platform. + */ + page_array[seg] = virt_to_page((void *)(va & PAGE_MASK)); if (do_crc) crypto_shash_update( c_tx->mpa_crc_hd, - (void *)(uintptr_t)va, + (void *)va, plen); } From 55195563ec29f80f984237b743de0e2b6ba4d093 Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Fri, 2 Sep 2022 10:45:06 +0100 Subject: [PATCH 193/228] ipv6: sr: fix out-of-bounds read when setting HMAC data. [ Upstream commit 84a53580c5d2138c7361c7c3eea5b31827e63b35 ] The SRv6 layer allows defining HMAC data that can later be used to sign IPv6 Segment Routing Headers. This configuration is realised via netlink through four attributes: SEG6_ATTR_HMACKEYID, SEG6_ATTR_SECRET, SEG6_ATTR_SECRETLEN and SEG6_ATTR_ALGID. Because the SECRETLEN attribute is decoupled from the actual length of the SECRET attribute, it is possible to provide invalid combinations (e.g., secret = "", secretlen = 64). This case is not checked in the code and with an appropriately crafted netlink message, an out-of-bounds read of up to 64 bytes (max secret length) can occur past the skb end pointer and into skb_shared_info: Breakpoint 1, seg6_genl_sethmac (skb=, info=) at net/ipv6/seg6.c:208 208 memcpy(hinfo->secret, secret, slen); (gdb) bt #0 seg6_genl_sethmac (skb=, info=) at net/ipv6/seg6.c:208 #1 0xffffffff81e012e9 in genl_family_rcv_msg_doit (skb=skb@entry=0xffff88800b1f9f00, nlh=nlh@entry=0xffff88800b1b7600, extack=extack@entry=0xffffc90000ba7af0, ops=ops@entry=0xffffc90000ba7a80, hdrlen=4, net=0xffffffff84237580 , family=, family=) at net/netlink/genetlink.c:731 #2 0xffffffff81e01435 in genl_family_rcv_msg (extack=0xffffc90000ba7af0, nlh=0xffff88800b1b7600, skb=0xffff88800b1f9f00, family=0xffffffff82fef6c0 ) at net/netlink/genetlink.c:775 #3 genl_rcv_msg (skb=0xffff88800b1f9f00, nlh=0xffff88800b1b7600, extack=0xffffc90000ba7af0) at net/netlink/genetlink.c:792 #4 0xffffffff81dfffc3 in netlink_rcv_skb (skb=skb@entry=0xffff88800b1f9f00, cb=cb@entry=0xffffffff81e01350 ) at net/netlink/af_netlink.c:2501 #5 0xffffffff81e00919 in genl_rcv (skb=0xffff88800b1f9f00) at net/netlink/genetlink.c:803 #6 0xffffffff81dff6ae in netlink_unicast_kernel (ssk=0xffff888010eec800, skb=0xffff88800b1f9f00, sk=0xffff888004aed000) at net/netlink/af_netlink.c:1319 #7 netlink_unicast (ssk=ssk@entry=0xffff888010eec800, skb=skb@entry=0xffff88800b1f9f00, portid=portid@entry=0, nonblock=) at net/netlink/af_netlink.c:1345 #8 0xffffffff81dff9a4 in netlink_sendmsg (sock=, msg=0xffffc90000ba7e48, len=) at net/netlink/af_netlink.c:1921 ... (gdb) p/x ((struct sk_buff *)0xffff88800b1f9f00)->head + ((struct sk_buff *)0xffff88800b1f9f00)->end $1 = 0xffff88800b1b76c0 (gdb) p/x secret $2 = 0xffff88800b1b76c0 (gdb) p slen $3 = 64 '@' The OOB data can then be read back from userspace by dumping HMAC state. This commit fixes this by ensuring SECRETLEN cannot exceed the actual length of SECRET. Reported-by: Lucas Leong Tested: verified that EINVAL is correctly returned when secretlen > len(secret) Fixes: 4f4853dc1c9c1 ("ipv6: sr: implement API to control SR HMAC structure") Signed-off-by: David Lebrun Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/ipv6/seg6.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c index fa6b64c95d3ae..0c7c6fc16c3c3 100644 --- a/net/ipv6/seg6.c +++ b/net/ipv6/seg6.c @@ -191,6 +191,11 @@ static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } + if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) { + err = -EINVAL; + goto out_unlock; + } + if (hinfo) { err = seg6_hmac_info_del(net, hmackeyid); if (err) From 819110054b14d7272b4188db997a3d80f75ab785 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Wed, 24 Aug 2022 09:10:36 +0300 Subject: [PATCH 194/228] IB/core: Fix a nested dead lock as part of ODP flow [ Upstream commit 85eaeb5058f0f04dffb124c97c86b4f18db0b833 ] Fix a nested dead lock as part of ODP flow by using mmput_async(). From the below call trace [1] can see that calling mmput() once we have the umem_odp->umem_mutex locked as required by ib_umem_odp_map_dma_and_lock() might trigger in the same task the exit_mmap()->__mmu_notifier_release()->mlx5_ib_invalidate_range() which may dead lock when trying to lock the same mutex. Moving to use mmput_async() will solve the problem as the above exit_mmap() flow will be called in other task and will be executed once the lock will be available. [1] [64843.077665] task:kworker/u133:2 state:D stack: 0 pid:80906 ppid: 2 flags:0x00004000 [64843.077672] Workqueue: mlx5_ib_page_fault mlx5_ib_eqe_pf_action [mlx5_ib] [64843.077719] Call Trace: [64843.077722] [64843.077724] __schedule+0x23d/0x590 [64843.077729] schedule+0x4e/0xb0 [64843.077735] schedule_preempt_disabled+0xe/0x10 [64843.077740] __mutex_lock.constprop.0+0x263/0x490 [64843.077747] __mutex_lock_slowpath+0x13/0x20 [64843.077752] mutex_lock+0x34/0x40 [64843.077758] mlx5_ib_invalidate_range+0x48/0x270 [mlx5_ib] [64843.077808] __mmu_notifier_release+0x1a4/0x200 [64843.077816] exit_mmap+0x1bc/0x200 [64843.077822] ? walk_page_range+0x9c/0x120 [64843.077828] ? __cond_resched+0x1a/0x50 [64843.077833] ? mutex_lock+0x13/0x40 [64843.077839] ? uprobe_clear_state+0xac/0x120 [64843.077860] mmput+0x5f/0x140 [64843.077867] ib_umem_odp_map_dma_and_lock+0x21b/0x580 [ib_core] [64843.077931] pagefault_real_mr+0x9a/0x140 [mlx5_ib] [64843.077962] pagefault_mr+0xb4/0x550 [mlx5_ib] [64843.077992] pagefault_single_data_segment.constprop.0+0x2ac/0x560 [mlx5_ib] [64843.078022] mlx5_ib_eqe_pf_action+0x528/0x780 [mlx5_ib] [64843.078051] process_one_work+0x22b/0x3d0 [64843.078059] worker_thread+0x53/0x410 [64843.078065] ? process_one_work+0x3d0/0x3d0 [64843.078073] kthread+0x12a/0x150 [64843.078079] ? set_kthread_struct+0x50/0x50 [64843.078085] ret_from_fork+0x22/0x30 [64843.078093] Fixes: 36f30e486dce ("IB/core: Improve ODP to use hmm_range_fault()") Reviewed-by: Maor Gottlieb Signed-off-by: Yishai Hadas Link: https://lore.kernel.org/r/74d93541ea533ef7daec6f126deb1072500aeb16.1661251841.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/core/umem_odp.c | 2 +- kernel/fork.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 7a47343d11f9f..b052de1b9ccb9 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -463,7 +463,7 @@ int ib_umem_odp_map_dma_and_lock(struct ib_umem_odp *umem_odp, u64 user_virt, mutex_unlock(&umem_odp->umem_mutex); out_put_mm: - mmput(owning_mm); + mmput_async(owning_mm); out_put_task: if (owning_process) put_task_struct(owning_process); diff --git a/kernel/fork.c b/kernel/fork.c index 89475c994ca91..908ba3c93893f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1153,6 +1153,7 @@ void mmput_async(struct mm_struct *mm) schedule_work(&mm->async_put_work); } } +EXPORT_SYMBOL_GPL(mmput_async); #endif /** From 5fbe35c94abca774cb89fc409ea648f486e9a22e Mon Sep 17 00:00:00 2001 From: Chris Mi Date: Mon, 29 Aug 2022 12:02:28 +0300 Subject: [PATCH 195/228] RDMA/mlx5: Set local port to one when accessing counters [ Upstream commit 74b30b3ad5cec95d2647e796d10137438a098bc1 ] When accessing Ports Performance Counters Register (PPCNT), local port must be one if it is Function-Per-Port HCA that HCA_CAP.num_ports is 1. The offending patch can change the local port to other values when accessing PPCNT after enabling switchdev mode. The following syndrome will be printed: # cat /sys/class/infiniband/rdmap4s0f0/ports/2/counters/* # dmesg mlx5_core 0000:04:00.0: mlx5_cmd_check:756:(pid 12450): ACCESS_REG(0x805) op_mod(0x1) failed, status bad parameter(0x3), syndrome (0x1e5585) Fix it by setting local port to one for Function-Per-Port HCA. Fixes: 210b1f78076f ("IB/mlx5: When not in dual port RoCE mode, use provided port as native") Reviewed-by: Mark Bloch Signed-off-by: Chris Mi Link: https://lore.kernel.org/r/6c5086c295c76211169e58dbd610fb0402360bab.1661763459.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/mlx5/mad.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index ec242a5a17a35..f6f2df855c2ed 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -166,6 +166,12 @@ static int process_pma_cmd(struct mlx5_ib_dev *dev, u32 port_num, mdev = dev->mdev; mdev_port_num = 1; } + if (MLX5_CAP_GEN(dev->mdev, num_ports) == 1) { + /* set local port to one for Function-Per-Port HCA. */ + mdev = dev->mdev; + mdev_port_num = 1; + } + /* Declaring support of extended counters */ if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) { struct ib_class_port_info cpi = {}; From 8ddd001cef5e82d19192e6861068463ecca5f556 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Fri, 2 Sep 2022 12:57:10 +0800 Subject: [PATCH 196/228] erofs: fix pcluster use-after-free on UP platforms [ Upstream commit 2f44013e39984c127c6efedf70e6b5f4e9dcf315 ] During stress testing with CONFIG_SMP disabled, KASAN reports as below: ================================================================== BUG: KASAN: use-after-free in __mutex_lock+0xe5/0xc30 Read of size 8 at addr ffff8881094223f8 by task stress/7789 CPU: 0 PID: 7789 Comm: stress Not tainted 6.0.0-rc1-00002-g0d53d2e882f9 #3 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 Call Trace: .. __mutex_lock+0xe5/0xc30 .. z_erofs_do_read_page+0x8ce/0x1560 .. z_erofs_readahead+0x31c/0x580 .. Freed by task 7787 kasan_save_stack+0x1e/0x40 kasan_set_track+0x20/0x30 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x190 kmem_cache_free+0xed/0x380 rcu_core+0x3d5/0xc90 __do_softirq+0x12d/0x389 Last potentially related work creation: kasan_save_stack+0x1e/0x40 __kasan_record_aux_stack+0x97/0xb0 call_rcu+0x3d/0x3f0 erofs_shrink_workstation+0x11f/0x210 erofs_shrink_scan+0xdc/0x170 shrink_slab.constprop.0+0x296/0x530 drop_slab+0x1c/0x70 drop_caches_sysctl_handler+0x70/0x80 proc_sys_call_handler+0x20a/0x2f0 vfs_write+0x555/0x6c0 ksys_write+0xbe/0x160 do_syscall_64+0x3b/0x90 The root cause is that erofs_workgroup_unfreeze() doesn't reset to orig_val thus it causes a race that the pcluster reuses unexpectedly before freeing. Since UP platforms are quite rare now, such path becomes unnecessary. Let's drop such specific-designed path directly instead. Fixes: 73f5c66df3e2 ("staging: erofs: fix `erofs_workgroup_{try_to_freeze, unfreeze}'") Reviewed-by: Yue Hu Reviewed-by: Chao Yu Link: https://lore.kernel.org/r/20220902045710.109530-1-hsiangkao@linux.alibaba.com Signed-off-by: Gao Xiang Signed-off-by: Sasha Levin --- fs/erofs/internal.h | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 9524e155b38fa..b77acf09726c6 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -143,7 +143,6 @@ struct erofs_workgroup { atomic_t refcount; }; -#if defined(CONFIG_SMP) static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp, int val) { @@ -172,34 +171,6 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) return atomic_cond_read_relaxed(&grp->refcount, VAL != EROFS_LOCKED_MAGIC); } -#else -static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp, - int val) -{ - preempt_disable(); - /* no need to spin on UP platforms, let's just disable preemption. */ - if (val != atomic_read(&grp->refcount)) { - preempt_enable(); - return false; - } - return true; -} - -static inline void erofs_workgroup_unfreeze(struct erofs_workgroup *grp, - int orig_val) -{ - preempt_enable(); -} - -static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp) -{ - int v = atomic_read(&grp->refcount); - - /* workgroup is never freezed on uniprocessor systems */ - DBG_BUGON(v == EROFS_LOCKED_MAGIC); - return v; -} -#endif /* !CONFIG_SMP */ #endif /* !CONFIG_EROFS_FS_ZIP */ /* we strictly follow PAGE_SIZE and no buffer head yet */ From 13c80a6c112467bab5e44d090767930555fc17a5 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 5 Sep 2022 13:54:17 +0300 Subject: [PATCH 197/228] nvme-tcp: fix UAF when detecting digest errors [ Upstream commit 160f3549a907a50e51a8518678ba2dcf2541abea ] We should also bail from the io_work loop when we set rd_enabled to true, so we don't attempt to read data from the socket when the TCP stream is already out-of-sync or corrupted. Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver") Reported-by: Daniel Wagner Signed-off-by: Sagi Grimberg Reviewed-by: Daniel Wagner Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- drivers/nvme/host/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 20138e132558c..2c6e031135716 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1209,7 +1209,7 @@ static void nvme_tcp_io_work(struct work_struct *w) else if (unlikely(result < 0)) return; - if (!pending) + if (!pending || !queue->rd_enabled) return; } while (!time_after(jiffies, deadline)); /* quota is exhausted */ From 8589bbfad2b403585e75a398be17e43c3e102e3b Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 5 Sep 2022 18:07:06 +0300 Subject: [PATCH 198/228] nvme-tcp: fix regression that causes sporadic requests to time out [ Upstream commit 3770a42bb8ceb856877699257a43c0585a5d2996 ] When we queue requests, we strive to batch as much as possible and also signal the network stack that more data is about to be sent over a socket with MSG_SENDPAGE_NOTLAST. This flag looks at the pending requests queued as well as queue->more_requests that is derived from the block layer last-in-batch indication. We set more_request=true when we flush the request directly from .queue_rq submission context (in nvme_tcp_send_all), however this is wrongly assuming that no other requests may be queued during the execution of nvme_tcp_send_all. Due to this, a race condition may happen where: 1. request X is queued as !last-in-batch 2. request X submission context calls nvme_tcp_send_all directly 3. nvme_tcp_send_all is preempted and schedules to a different cpu 4. request Y is queued as last-in-batch 5. nvme_tcp_send_all context sends request X+Y, however signals for both MSG_SENDPAGE_NOTLAST because queue->more_requests=true. ==> none of the requests is pushed down to the wire as the network stack is waiting for more data, both requests timeout. To fix this, we eliminate queue->more_requests and only rely on the queue req_list and send_list to be not-empty. Fixes: 122e5b9f3d37 ("nvme-tcp: optimize network stack with setting msg flags according to batch size") Reported-by: Jonathan Nicklin Signed-off-by: Sagi Grimberg Tested-by: Jonathan Nicklin Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- drivers/nvme/host/tcp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 2c6e031135716..96d8d7844e846 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -119,7 +119,6 @@ struct nvme_tcp_queue { struct mutex send_mutex; struct llist_head req_list; struct list_head send_list; - bool more_requests; /* recv state */ void *pdu; @@ -315,7 +314,7 @@ static inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue) static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue) { return !list_empty(&queue->send_list) || - !llist_empty(&queue->req_list) || queue->more_requests; + !llist_empty(&queue->req_list); } static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req, @@ -334,9 +333,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req, */ if (queue->io_cpu == raw_smp_processor_id() && sync && empty && mutex_trylock(&queue->send_mutex)) { - queue->more_requests = !last; nvme_tcp_send_all(queue); - queue->more_requests = false; mutex_unlock(&queue->send_mutex); } From a96b1d33ec71e56f8b0cb9d9b0c42475bf262b99 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sat, 3 Sep 2022 08:10:23 -0400 Subject: [PATCH 199/228] tcp: fix early ETIMEDOUT after spurious non-SACK RTO [ Upstream commit 686dc2db2a0fdc1d34b424ec2c0a735becd8d62b ] Fix a bug reported and analyzed by Nagaraj Arankal, where the handling of a spurious non-SACK RTO could cause a connection to fail to clear retrans_stamp, causing a later RTO to very prematurely time out the connection with ETIMEDOUT. Here is the buggy scenario, expanding upon Nagaraj Arankal's excellent report: (*1) Send one data packet on a non-SACK connection (*2) Because no ACK packet is received, the packet is retransmitted and we enter CA_Loss; but this retransmission is spurious. (*3) The ACK for the original data is received. The transmitted packet is acknowledged. The TCP timestamp is before the retrans_stamp, so tcp_may_undo() returns true, and tcp_try_undo_loss() returns true without changing state to Open (because tcp_is_sack() is false), and tcp_process_loss() returns without calling tcp_try_undo_recovery(). Normally after undoing a CA_Loss episode, tcp_fastretrans_alert() would see that the connection has returned to CA_Open and fall through and call tcp_try_to_open(), which would set retrans_stamp to 0. However, for non-SACK connections we hold the connection in CA_Loss, so do not fall through to call tcp_try_to_open() and do not set retrans_stamp to 0. So retrans_stamp is (erroneously) still non-zero. At this point the first "retransmission event" has passed and been recovered from. Any future retransmission is a completely new "event". However, retrans_stamp is erroneously still set. (And we are still in CA_Loss, which is correct.) (*4) After 16 minutes (to correspond with tcp_retries2=15), a new data packet is sent. Note: No data is transmitted between (*3) and (*4) and we disabled keep alives. The socket's timeout SHOULD be calculated from this point in time, but instead it's calculated from the prior "event" 16 minutes ago (step (*2)). (*5) Because no ACK packet is received, the packet is retransmitted. (*6) At the time of the 2nd retransmission, the socket returns ETIMEDOUT, prematurely, because retrans_stamp is (erroneously) too far in the past (set at the time of (*2)). This commit fixes this bug by ensuring that we reuse in tcp_try_undo_loss() the same careful logic for non-SACK connections that we have in tcp_try_undo_recovery(). To avoid duplicating logic, we factor out that logic into a new tcp_is_non_sack_preventing_reopen() helper and call that helper from both undo functions. Fixes: da34ac7626b5 ("tcp: only undo on partial ACKs in CA_Loss") Reported-by: Nagaraj Arankal Link: https://lore.kernel.org/all/SJ0PR84MB1847BE6C24D274C46A1B9B0EB27A9@SJ0PR84MB1847.NAMPRD84.PROD.OUTLOOK.COM/ Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20220903121023.866900-1-ncardwell.kernel@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv4/tcp_input.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7fd7e7cba0c92..686e210d89c21 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2506,6 +2506,21 @@ static inline bool tcp_may_undo(const struct tcp_sock *tp) return tp->undo_marker && (!tp->undo_retrans || tcp_packet_delayed(tp)); } +static bool tcp_is_non_sack_preventing_reopen(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) { + /* Hold old state until something *above* high_seq + * is ACKed. For Reno it is MUST to prevent false + * fast retransmits (RFC2582). SACK TCP is safe. */ + if (!tcp_any_retrans_done(sk)) + tp->retrans_stamp = 0; + return true; + } + return false; +} + /* People celebrate: "We love our President!" */ static bool tcp_try_undo_recovery(struct sock *sk) { @@ -2528,14 +2543,8 @@ static bool tcp_try_undo_recovery(struct sock *sk) } else if (tp->rack.reo_wnd_persist) { tp->rack.reo_wnd_persist--; } - if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) { - /* Hold old state until something *above* high_seq - * is ACKed. For Reno it is MUST to prevent false - * fast retransmits (RFC2582). SACK TCP is safe. */ - if (!tcp_any_retrans_done(sk)) - tp->retrans_stamp = 0; + if (tcp_is_non_sack_preventing_reopen(sk)) return true; - } tcp_set_ca_state(sk, TCP_CA_Open); tp->is_sack_reneg = 0; return false; @@ -2571,6 +2580,8 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSPURIOUSRTOS); inet_csk(sk)->icsk_retransmits = 0; + if (tcp_is_non_sack_preventing_reopen(sk)) + return true; if (frto_undo || tcp_is_sack(tp)) { tcp_set_ca_state(sk, TCP_CA_Open); tp->is_sack_reneg = 0; From a1d7c8647c180a3d1b4c68aabe4b54c953679006 Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Tue, 6 Sep 2022 09:39:28 +0200 Subject: [PATCH 200/228] nvmet: fix mar and mor off-by-one errors [ Upstream commit b7e97872a65e1d57b4451769610554c131f37a0a ] Maximum Active Resources (MAR) and Maximum Open Resources (MOR) are 0's based vales where a value of 0xffffffff indicates that there is no limit. Decrement the values that are returned by bdev_max_open_zones and bdev_max_active_zones as the block layer helpers are not 0's based. A 0 returned by the block layer helpers indicates no limit, thus convert it to 0xffffffff (U32_MAX). Fixes: aaf2e048af27 ("nvmet: add ZBD over ZNS backend support") Suggested-by: Niklas Cassel Signed-off-by: Dennis Maisenbacher Reviewed-by: Chaitanya Kulkarni Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- drivers/nvme/target/zns.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index 235553337fb2d..1466698751c55 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -100,6 +100,7 @@ void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req) struct nvme_id_ns_zns *id_zns; u64 zsze; u16 status; + u32 mar, mor; if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) { req->error_loc = offsetof(struct nvme_identify, nsid); @@ -126,8 +127,20 @@ void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req) zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >> req->ns->blksize_shift; id_zns->lbafe[0].zsze = cpu_to_le64(zsze); - id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev)); - id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev)); + + mor = bdev_max_open_zones(req->ns->bdev); + if (!mor) + mor = U32_MAX; + else + mor--; + id_zns->mor = cpu_to_le32(mor); + + mar = bdev_max_active_zones(req->ns->bdev); + if (!mar) + mar = U32_MAX; + else + mar--; + id_zns->mar = cpu_to_le32(mar); done: status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns)); From c1872dfde6f7184bcd47c67ce50e3a8a4a22c858 Mon Sep 17 00:00:00 2001 From: Sindhu-Devale Date: Tue, 6 Sep 2022 17:32:40 -0500 Subject: [PATCH 201/228] RDMA/irdma: Report the correct max cqes from query device [ Upstream commit 12faad5e5cf2372af2d51f348b697b5edf838daf ] Report the correct max cqes available to an application taking into account a reserved entry to detect overflow. Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs") Signed-off-by: Sindhu-Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20220906223244.1119-2-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index cac4fb228b9b0..adb0e0774256c 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -36,7 +36,7 @@ static int irdma_query_device(struct ib_device *ibdev, props->max_send_sge = hw_attrs->uk_attrs.max_hw_wq_frags; props->max_recv_sge = hw_attrs->uk_attrs.max_hw_wq_frags; props->max_cq = rf->max_cq - rf->used_cqs; - props->max_cqe = rf->max_cqe; + props->max_cqe = rf->max_cqe - 1; props->max_mr = rf->max_mr - rf->used_mrs; props->max_mw = props->max_mr; props->max_pd = rf->max_pd - rf->used_pds; From 3ca173b217f461334093538c3c802dcb64877e97 Mon Sep 17 00:00:00 2001 From: Sindhu-Devale Date: Tue, 6 Sep 2022 17:32:42 -0500 Subject: [PATCH 202/228] RDMA/irdma: Return correct WC error for bind operation failure [ Upstream commit dcb23bbb1de7e009875fdfac2b8a9808a9319cc6 ] When a QP and a MR on a local host are in different PDs, the HW generates an asynchronous event (AE). The same AE is generated when a QP and a MW are in different PDs during a bind operation. Return the more appropriate IBV_WC_MW_BIND_ERR for the latter case by checking the OP type from the CQE in error. Fixes: 551c46edc769 ("RDMA/irdma: Add user/kernel shared libraries") Signed-off-by: Sindhu-Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20220906223244.1119-4-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/uk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index 9b544a3b12886..7e6c3ba8df6ab 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -1068,6 +1068,7 @@ irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, struct irdma_cq_poll_info *info) enum irdma_status_code ret_code; bool move_cq_head = true; u8 polarity; + u8 op_type; bool ext_valid; __le64 *ext_cqe; @@ -1250,7 +1251,6 @@ irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, struct irdma_cq_poll_info *info) do { __le64 *sw_wqe; u64 wqe_qword; - u8 op_type; u32 tail; tail = qp->sq_ring.tail; @@ -1267,6 +1267,8 @@ irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, struct irdma_cq_poll_info *info) break; } } while (1); + if (op_type == IRDMA_OP_TYPE_BIND_MW && info->minor_err == FLUSH_PROT_ERR) + info->minor_err = FLUSH_MW_BIND_ERR; qp->sq_flush_seen = true; if (!IRDMA_RING_MORE_WORK(qp->sq_ring)) qp->sq_flush_complete = true; From a600a9babad635a1126a693d343b96d00ce76a19 Mon Sep 17 00:00:00 2001 From: Sindhu-Devale Date: Tue, 6 Sep 2022 17:32:44 -0500 Subject: [PATCH 203/228] RDMA/irdma: Report RNR NAK generation in device caps [ Upstream commit a261786fdc0a5bed2e5f994dcc0ffeeeb0d662c7 ] Report RNR NAK generation when device capabilities are queried Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs") Signed-off-by: Sindhu-Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20220906223244.1119-6-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/verbs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index adb0e0774256c..5275616398d83 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -43,8 +43,11 @@ static int irdma_query_device(struct ib_device *ibdev, props->max_sge_rd = hw_attrs->uk_attrs.max_hw_read_sges; props->max_qp_rd_atom = hw_attrs->max_hw_ird; props->max_qp_init_rd_atom = hw_attrs->max_hw_ord; - if (rdma_protocol_roce(ibdev, 1)) + if (rdma_protocol_roce(ibdev, 1)) { + props->device_cap_flags |= IB_DEVICE_RC_RNR_NAK_GEN; props->max_pkeys = IRDMA_PKEY_TBL_SZ; + } + props->max_ah = rf->max_ah; props->max_mcast_grp = rf->max_mcg; props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX; From 4519d4e32f986356fb7b29f211d858283510f6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Mon, 5 Sep 2022 21:21:36 +0200 Subject: [PATCH 204/228] sch_sfb: Also store skb len before calling child enqueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2f09707d0c972120bf794cfe0f0c67e2c2ddb252 ] Cong Wang noticed that the previous fix for sch_sfb accessing the queued skb after enqueueing it to a child qdisc was incomplete: the SFB enqueue function was also calling qdisc_qstats_backlog_inc() after enqueue, which reads the pkt len from the skb cb field. Fix this by also storing the skb len, and using the stored value to increment the backlog after enqueueing. Fixes: 9efd23297cca ("sch_sfb: Don't assume the skb is still around after enqueueing to child") Signed-off-by: Toke Høiland-Jørgensen Acked-by: Cong Wang Link: https://lore.kernel.org/r/20220905192137.965549-1-toke@toke.dk Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/sched/sch_sfb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 0d761f454ae8b..2829455211f8c 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -281,6 +281,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, { struct sfb_sched_data *q = qdisc_priv(sch); + unsigned int len = qdisc_pkt_len(skb); struct Qdisc *child = q->qdisc; struct tcf_proto *fl; struct sfb_skb_cb cb; @@ -403,7 +404,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, memcpy(&cb, sfb_skb_cb(skb), sizeof(cb)); ret = qdisc_enqueue(skb, child, to_free); if (likely(ret == NET_XMIT_SUCCESS)) { - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; increment_qlen(&cb, q); } else if (net_xmit_drop_count(ret)) { From 159d35a87ec3cc032e31933b5e35273298535087 Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Thu, 8 Sep 2022 15:00:30 +0800 Subject: [PATCH 205/228] perf script: Fix Cannot print 'iregs' field for hybrid systems [ Upstream commit 82b2425fad2dd47204b3da589b679220f8aacc0e ] Commit b91e5492f9d7ca89 ("perf record: Add a dummy event on hybrid systems to collect metadata records") adds a dummy event on hybrid systems to fix the symbol "unknown" issue when the workload is created in a P-core but runs on an E-core. The added dummy event will cause "perf script -F iregs" to fail. Dummy events do not have "iregs" attribute set, so when we do evsel__check_attr, the "iregs" attribute check will fail, so the issue happened. The following commit [1] has fixed a similar issue by skipping the attr check for the dummy event because it does not have any samples anyway. It works okay for the normal mode, but the issue still happened when running the test in the pipe mode. In the pipe mode, it calls process_attr() which still checks the attr for the dummy event. This commit fixed the issue by skipping the attr check for the dummy event in the API evsel__check_attr, Otherwise, we have to patch everywhere when evsel__check_attr() is called. Before: #./perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call:p -c 1000 --per-thread true 2>/dev/null|./perf script -F iregs |head -5 Samples for 'dummy:HG' event do not have IREGS attribute set. Cannot print 'iregs' field. 0x120 [0x90]: failed to process type: 64 # After: # ./perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call:p -c 1000 --per-thread true 2>/dev/null|./perf script -F iregs |head -5 ABI:2 CX:0x55b8efa87000 DX:0x55b8efa7e000 DI:0xffffba5e625efbb0 R8:0xffff90e51f8ae100 ABI:2 CX:0x7f1dae1e4000 DX:0xd0 DI:0xffff90e18c675ac0 R8:0x71 ABI:2 CX:0xcc0 DX:0x1 DI:0xffff90e199880240 R8:0x0 ABI:2 CX:0xffff90e180dd7500 DX:0xffff90e180dd7500 DI:0xffff90e180043500 R8:0x1 ABI:2 CX:0x50 DX:0xffff90e18c583bd0 DI:0xffff90e1998803c0 R8:0x58 # [1]https://lore.kernel.org/lkml/20220831124041.219925-1-jolsa@kernel.org/ Fixes: b91e5492f9d7ca89 ("perf record: Add a dummy event on hybrid systems to collect metadata records") Suggested-by: Namhyung Kim Signed-off-by: Xing Zhengjun Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ian Rogers Cc: Ingo Molnar Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20220908070030.3455164-1-zhengjun.xing@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/perf/builtin-script.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index cb3d81adf5ca8..c6c40191933d4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -435,6 +435,9 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) struct perf_event_attr *attr = &evsel->core.attr; bool allow_user_set; + if (evsel__is_dummy_event(evsel)) + return 0; + if (perf_header__has_feat(&session->header, HEADER_STAT)) return 0; From 30a455ac385e967c1d56bd8617f9baaeaf2abb58 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Mon, 5 Sep 2022 09:28:04 -0500 Subject: [PATCH 206/228] hwmon: (tps23861) fix byte order in resistance register commit 1f05f65bddd6958d25b133f886da49c1d4bff3fa upstream. The tps23861 registers are little-endian, and regmap_read_bulk() does not do byte order conversion. On BE machines, the bytes were swapped, and the interpretation of the resistance value was incorrect. To make it work on both big and little-endian machines, use le16_to_cpu() to convert the resitance register to host byte order. Signed-off-by: Alexandru Gagniuc Fixes: fff7b8ab22554 ("hwmon: add Texas Instruments TPS23861 driver") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20220905142806.110598-1-mr.nuke.me@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/tps23861.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index 8bd6435c13e82..2148fd543bb4b 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -489,18 +489,20 @@ static char *tps23861_port_poe_plus_status(struct tps23861_data *data, int port) static int tps23861_port_resistance(struct tps23861_data *data, int port) { - u16 regval; + unsigned int raw_val; + __le16 regval; regmap_bulk_read(data->regmap, PORT_1_RESISTANCE_LSB + PORT_N_RESISTANCE_LSB_OFFSET * (port - 1), ®val, 2); - switch (FIELD_GET(PORT_RESISTANCE_RSN_MASK, regval)) { + raw_val = le16_to_cpu(regval); + switch (FIELD_GET(PORT_RESISTANCE_RSN_MASK, raw_val)) { case PORT_RESISTANCE_RSN_OTHER: - return (FIELD_GET(PORT_RESISTANCE_MASK, regval) * RESISTANCE_LSB) / 10000; + return (FIELD_GET(PORT_RESISTANCE_MASK, raw_val) * RESISTANCE_LSB) / 10000; case PORT_RESISTANCE_RSN_LOW: - return (FIELD_GET(PORT_RESISTANCE_MASK, regval) * RESISTANCE_LSB_LOW) / 10000; + return (FIELD_GET(PORT_RESISTANCE_MASK, raw_val) * RESISTANCE_LSB_LOW) / 10000; case PORT_RESISTANCE_RSN_SHORT: case PORT_RESISTANCE_RSN_OPEN: default: From 4643fbc79ded71531aa70c625e2305340035e303 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 27 Jul 2022 12:08:14 +0300 Subject: [PATCH 207/228] ASoC: mchp-spdiftx: remove references to mchp_i2s_caps commit 403fcb5118a0f4091001a537e76923031fb45eaf upstream. Remove references to struct mchp_i2s_caps as they are not used. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220727090814.2446111-3-claudiu.beznea@microchip.com Signed-off-by: Mark Brown Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- sound/soc/atmel/mchp-spdiftx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index d243800464352..9b40df2c39f9b 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -196,7 +196,6 @@ struct mchp_spdiftx_dev { struct clk *pclk; struct clk *gclk; unsigned int fmt; - const struct mchp_i2s_caps *caps; int gclk_enabled:1; }; @@ -766,8 +765,6 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = { MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids); static int mchp_spdiftx_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct mchp_spdiftx_dev *dev; struct resource *mem; struct regmap *regmap; @@ -781,11 +778,6 @@ static int mchp_spdiftx_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - /* Get hardware capabilities. */ - match = of_match_node(mchp_spdiftx_dt_ids, np); - if (match) - dev->caps = match->data; - /* Map I/O registers. */ base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) From 166ae43f02fb6fff9855f1c783d99a6011460cae Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 9 Aug 2022 18:08:09 -0700 Subject: [PATCH 208/228] ASoC: mchp-spdiftx: Fix clang -Wbitfield-constant-conversion commit 5c5c2baad2b55cc0a4b190266889959642298f79 upstream. A recent change in clang strengthened its -Wbitfield-constant-conversion to warn when 1 is assigned to a 1-bit signed integer bitfield, as it can only be 0 or -1, not 1: sound/soc/atmel/mchp-spdiftx.c:505:20: error: implicit truncation from 'int' to bit-field changes value from 1 to -1 [-Werror,-Wbitfield-constant-conversion] dev->gclk_enabled = 1; ^ ~ 1 error generated. The actual value of the field is never checked, just that it is not zero, so there is not a real bug here. However, it is simple enough to silence the warning by making the bitfield unsigned, which matches the mchp-spdifrx driver. Fixes: 06ca24e98e6b ("ASoC: mchp-spdiftx: add driver for S/PDIF TX Controller") Link: https://github.com/ClangBuiltLinux/linux/issues/1686 Link: https://github.com/llvm/llvm-project/commit/82afc9b169a67e8b8a1862fb9c41a2cd974d6691 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20220810010809.2024482-1-nathan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/atmel/mchp-spdiftx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 9b40df2c39f9b..bcca1cf3cd7b6 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -196,7 +196,7 @@ struct mchp_spdiftx_dev { struct clk *pclk; struct clk *gclk; unsigned int fmt; - int gclk_enabled:1; + unsigned int gclk_enabled:1; }; static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev) From 12202e0f74fd0bb5aea84950ce7eab8bee4494cc Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Tue, 23 Aug 2022 19:17:25 +0800 Subject: [PATCH 209/228] MIPS: loongson32: ls1c: Fix hang during startup [ Upstream commit 35508d2424097f9b6a1a17aac94f702767035616 ] The RTCCTRL reg of LS1C is obselete. Writing this reg will cause system hang. Fixes: 60219c563c9b6 ("MIPS: Add RTC support for Loongson1C board") Signed-off-by: Yang Ling Tested-by: Keguang Zhang Acked-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer Signed-off-by: Sasha Levin --- arch/mips/loongson32/ls1c/board.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c index e9de6da0ce51f..9dcfe9de55b0a 100644 --- a/arch/mips/loongson32/ls1c/board.c +++ b/arch/mips/loongson32/ls1c/board.c @@ -15,7 +15,6 @@ static struct platform_device *ls1c_platform_devices[] __initdata = { static int __init ls1c_platform_init(void) { ls1x_serial_set_uartclk(&ls1x_uart_pdev); - ls1x_rtc_set_extclk(&ls1x_rtc_pdev); return platform_add_devices(ls1c_platform_devices, ARRAY_SIZE(ls1c_platform_devices)); From 657d9d8ac3e602b92c0f6e02cd07ac22c95b7a54 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 1 Sep 2022 10:12:52 +0900 Subject: [PATCH 210/228] kbuild: disable header exports for UML in a straightforward way [ Upstream commit 1b620d539ccc18a1aca1613d9ff078115a7891a1 ] Previously 'make ARCH=um headers' stopped because of missing arch/um/include/uapi/asm/Kbuild. The error is not shown since commit ed102bf2afed ("um: Fix W=1 missing-include-dirs warnings") added arch/um/include/uapi/asm/Kbuild. Hard-code the unsupported architecture, so it works like before. Fixes: ed102bf2afed ("um: Fix W=1 missing-include-dirs warnings") Signed-off-by: Masahiro Yamada Acked-by: Richard Weinberger Signed-off-by: Sasha Levin --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eca45b7be9c1e..32253ea989217 100644 --- a/Makefile +++ b/Makefile @@ -1332,8 +1332,7 @@ hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj PHONY += headers headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts - $(if $(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/Kbuild),, \ - $(error Headers not exportable for the $(SRCARCH) architecture)) + $(if $(filter um, $(SRCARCH)), $(error Headers not exportable for UML)) $(Q)$(MAKE) $(hdr-inst)=include/uapi $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi From 39d9de5872b622ceaa739be6a9c632001882cd65 Mon Sep 17 00:00:00 2001 From: Przemyslaw Patynowski Date: Wed, 8 Jun 2022 13:52:48 +0200 Subject: [PATCH 211/228] i40e: Refactor tc mqprio checks [ Upstream commit 2313e69c84c024a85d017a60ae925085de47530a ] Refactor bitwise checks for whether TC MQPRIO is enabled into one single method for improved readability. Signed-off-by: Przemyslaw Patynowski Signed-off-by: Jan Sokolowski Tested-by: Bharathi Sreenivas Signed-off-by: Tony Nguyen Stable-dep-of: 45bb006d3c92 ("i40e: Fix ADQ rate limiting for PF") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/i40e/i40e.h | 14 +++++++++++++ .../net/ethernet/intel/i40e/i40e_ethtool.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 20 +++++++++---------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 210f09118edea..0f19c237cb587 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1286,4 +1286,18 @@ int i40e_add_del_cloud_filter(struct i40e_vsi *vsi, int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi, struct i40e_cloud_filter *filter, bool add); + +/** + * i40e_is_tc_mqprio_enabled - check if TC MQPRIO is enabled on PF + * @pf: pointer to a pf. + * + * Check and return value of flag I40E_FLAG_TC_MQPRIO. + * + * Return: I40E_FLAG_TC_MQPRIO set state. + **/ +static inline u32 i40e_is_tc_mqprio_enabled(struct i40e_pf *pf) +{ + return pf->flags & I40E_FLAG_TC_MQPRIO; +} + #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 669ae53f4c728..8e770c5e181ea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -4921,7 +4921,7 @@ static int i40e_set_channels(struct net_device *dev, /* We do not support setting channels via ethtool when TCs are * configured through mqprio */ - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) return -EINVAL; /* verify they are not requesting separate vectors */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 536f9198bd47a..f373072dd3b30 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5320,7 +5320,7 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) u8 num_tc = 0; struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config; - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) return pf->vsi[pf->lan_vsi]->mqprio_qopt.qopt.num_tc; /* If neither MQPRIO nor DCB is enabled, then always use single TC */ @@ -5352,7 +5352,7 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) **/ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) { - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) return i40e_mqprio_get_enabled_tc(pf); /* If neither MQPRIO nor DCB is enabled for this PF then just return @@ -5449,7 +5449,7 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, int i; /* There is no need to reset BW when mqprio mode is on. */ - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) return 0; if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) { ret = i40e_set_bw_limit(vsi, vsi->seid, 0); @@ -5521,7 +5521,7 @@ static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc) vsi->tc_config.tc_info[i].qoffset); } - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) return; /* Assign UP2TC map for the VSI */ @@ -5682,7 +5682,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ctxt.vf_num = 0; ctxt.uplink_seid = vsi->uplink_seid; ctxt.info = vsi->info; - if (vsi->back->flags & I40E_FLAG_TC_MQPRIO) { + if (i40e_is_tc_mqprio_enabled(pf)) { ret = i40e_vsi_setup_queue_map_mqprio(vsi, &ctxt, enabled_tc); if (ret) goto out; @@ -6406,7 +6406,7 @@ int i40e_create_queue_channel(struct i40e_vsi *vsi, pf->flags |= I40E_FLAG_VEB_MODE_ENABLED; if (vsi->type == I40E_VSI_MAIN) { - if (pf->flags & I40E_FLAG_TC_MQPRIO) + if (i40e_is_tc_mqprio_enabled(pf)) i40e_do_reset(pf, I40E_PF_RESET_FLAG, true); else i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG); @@ -7800,7 +7800,7 @@ static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev) netdev_info(netdev, "Macvlans are not supported when DCB is enabled\n"); return ERR_PTR(-EINVAL); } - if ((pf->flags & I40E_FLAG_TC_MQPRIO)) { + if (i40e_is_tc_mqprio_enabled(pf)) { netdev_info(netdev, "Macvlans are not supported when HW TC offload is on\n"); return ERR_PTR(-EINVAL); } @@ -8053,7 +8053,7 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data) /* Quiesce VSI queues */ i40e_quiesce_vsi(vsi); - if (!hw && !(pf->flags & I40E_FLAG_TC_MQPRIO)) + if (!hw && !i40e_is_tc_mqprio_enabled(pf)) i40e_remove_queue_channels(vsi); /* Configure VSI for enabled TCs */ @@ -8077,7 +8077,7 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data) "Setup channel (id:%u) utilizing num_queues %d\n", vsi->seid, vsi->tc_config.tc_info[0].qcount); - if (pf->flags & I40E_FLAG_TC_MQPRIO) { + if (i40e_is_tc_mqprio_enabled(pf)) { if (vsi->mqprio_qopt.max_rate[0]) { u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0]; @@ -10731,7 +10731,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) * unless I40E_FLAG_TC_MQPRIO was enabled or DCB * is not supported with new link speed */ - if (pf->flags & I40E_FLAG_TC_MQPRIO) { + if (i40e_is_tc_mqprio_enabled(pf)) { i40e_aq_set_dcb_parameters(hw, false, NULL); } else { if (I40E_IS_X710TL_DEVICE(hw->device_id) && From df82f5ce4f507b62547e8d0a629a38f0a5bc64aa Mon Sep 17 00:00:00 2001 From: Przemyslaw Patynowski Date: Tue, 9 Aug 2022 10:57:44 +0200 Subject: [PATCH 212/228] i40e: Fix ADQ rate limiting for PF [ Upstream commit 45bb006d3c924b1201ed43c87a96b437662dcaa8 ] Fix HW rate limiting for ADQ. Fallback to kernel queue selection for ADQ, as it is network stack that decides which queue to use for transmit with ADQ configured. Reset PF after creation of VMDq2 VSIs required for ADQ, as to reprogram TX queue contexts in i40e_configure_tx_ring. Without this patch PF would limit TX rate only according to TC0. Fixes: a9ce82f744dc ("i40e: Enable 'channel' mode in mqprio for TC configs") Signed-off-by: Przemyslaw Patynowski Signed-off-by: Jan Sokolowski Tested-by: Bharathi Sreenivas Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f373072dd3b30..ce6eea7a60027 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6517,6 +6517,9 @@ static int i40e_configure_queue_channels(struct i40e_vsi *vsi) vsi->tc_seid_map[i] = ch->seid; } } + + /* reset to reconfigure TX queue contexts */ + i40e_do_reset(vsi->back, I40E_PF_RESET_FLAG, true); return ret; err_free: diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index d3a4a33977ee8..326fd25d055f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -3651,7 +3651,8 @@ u16 i40e_lan_select_queue(struct net_device *netdev, u8 prio; /* is DCB enabled at all? */ - if (vsi->tc_config.numtc == 1) + if (vsi->tc_config.numtc == 1 || + i40e_is_tc_mqprio_enabled(vsi->back)) return netdev_pick_tx(netdev, skb, sb_dev); prio = skb->priority; From 4f8d658848087b5efd3c84658fb145474ca0d336 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 19 Aug 2022 16:45:37 +0800 Subject: [PATCH 213/228] swiotlb: avoid potential left shift overflow [ Upstream commit 3f0461613ebcdc8c4073e235053d06d5aa58750f ] The second operand passed to slot_addr() is declared as int or unsigned int in all call sites. The left-shift to get the offset of a slot can overflow if swiotlb size is larger than 4G. Convert the macro to an inline function and declare the second argument as phys_addr_t to avoid the potential overflow. Fixes: 26a7e094783d ("swiotlb: refactor swiotlb_tbl_map_single") Signed-off-by: Chao Gao Reviewed-by: Dongli Zhang Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- kernel/dma/swiotlb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index e62fb7a4da694..018f140aaaf4e 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -435,7 +435,10 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size } } -#define slot_addr(start, idx) ((start) + ((idx) << IO_TLB_SHIFT)) +static inline phys_addr_t slot_addr(phys_addr_t start, phys_addr_t idx) +{ + return start + (idx << IO_TLB_SHIFT); +} /* * Carefully handle integer overflow which can occur when boundary_mask == ~0UL. From a557ae094207cffcf0d612c7bdbef7513519683a Mon Sep 17 00:00:00 2001 From: John Sperbeck Date: Mon, 1 Aug 2022 19:22:29 +0000 Subject: [PATCH 214/228] iommu/amd: use full 64-bit value in build_completion_wait() [ Upstream commit 94a568ce32038d8ff9257004bb4632e60eb43a49 ] We started using a 64 bit completion value. Unfortunately, we only stored the low 32-bits, so a very large completion value would never be matched in iommu_completion_wait(). Fixes: c69d89aff393 ("iommu/amd: Use 4K page for completion wait write-back semaphore") Signed-off-by: John Sperbeck Link: https://lore.kernel.org/r/20220801192229.3358786-1-jsperbeck@google.com Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd/iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index e23e70af718f1..7154fb551ddc9 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -852,7 +852,8 @@ static void build_completion_wait(struct iommu_cmd *cmd, memset(cmd, 0, sizeof(*cmd)); cmd->data[0] = lower_32_bits(paddr) | CMD_COMPL_WAIT_STORE_MASK; cmd->data[1] = upper_32_bits(paddr); - cmd->data[2] = data; + cmd->data[2] = lower_32_bits(data); + cmd->data[3] = upper_32_bits(data); CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); } From 4b198c41d736c1c4c4974fd53cd03d632abdb6be Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sat, 13 Aug 2022 19:45:21 +0200 Subject: [PATCH 215/228] s390/boot: fix absolute zero lowcore corruption on boot [ Upstream commit 12dd19c159659ec9050f45dc8a2ff3c3917f4be3 ] Crash dump always starts on CPU0. In case CPU0 is offline the prefix page is not installed and the absolute zero lowcore is used. However, struct lowcore::mcesad is never assigned and stays zero. That leads to __machine_kdump() -> save_vx_regs() call silently stores vector registers to the absolute lowcore at 0x11b0 offset. Fixes: a62bc0739253 ("s390/kdump: add support for vector extension") Reviewed-by: Heiko Carstens Signed-off-by: Alexander Gordeev Signed-off-by: Vasily Gorbik Signed-off-by: Sasha Levin --- arch/s390/kernel/nmi.c | 2 +- arch/s390/kernel/setup.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index a50f2ff1b00e8..383b4799b6dd3 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -62,7 +62,7 @@ static inline unsigned long nmi_get_mcesa_size(void) * The structure is required for machine check happening early in * the boot process. */ -static struct mcesa boot_mcesa __initdata __aligned(MCESA_MAX_SIZE); +static struct mcesa boot_mcesa __aligned(MCESA_MAX_SIZE); void __init nmi_alloc_boot_cpu(struct lowcore *lc) { diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 6b1a8697fae8d..4dfe37b068898 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -484,6 +484,7 @@ static void __init setup_lowcore_dat_off(void) put_abs_lowcore(restart_data, lc->restart_data); put_abs_lowcore(restart_source, lc->restart_source); put_abs_lowcore(restart_psw, lc->restart_psw); + put_abs_lowcore(mcesad, lc->mcesad); lc->spinlock_lockval = arch_spin_lockval(0); lc->spinlock_index = 0; From 000f3353231e1596634c04b09ee29ac675bfc19a Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 8 Sep 2022 15:24:30 +0000 Subject: [PATCH 216/228] hwmon: (mr75203) fix VM sensor allocation when "intel,vm-map" not defined [ Upstream commit 81114fc3d27bf5b06b2137d2fd2b63da656a8b90 ] Bug - in case "intel,vm-map" is missing in device-tree ,'num' is set to 0, and no voltage channel infos are allocated. The reason num is set to 0 when "intel,vm-map" is missing is to set the entire pvt->vm_idx[] with incremental channel numbers, but it didn't take into consideration that same num is used later in devm_kcalloc(). If "intel,vm-map" does exist there is no need to set the unspecified channels with incremental numbers, because the unspecified channels can't be accessed in pvt_read_in() which is the only other place besides the probe functions that uses pvt->vm_idx[]. This change fixes the bug by moving the incremental channel numbers setting to be done only if "intel,vm-map" property is defined (starting loop from 0), and removing 'num = 0'. Fixes: 9d823351a337 ("hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller") Signed-off-by: Eliav Farber Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220908152449.35457-3-farbere@amazon.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/mr75203.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 1ba1e31459690..36cbc86033ce9 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -594,7 +594,12 @@ static int mr75203_probe(struct platform_device *pdev) ret = device_property_read_u8_array(dev, "intel,vm-map", pvt->vm_idx, vm_num); if (ret) { - num = 0; + /* + * Incase intel,vm-map property is not defined, we + * assume incremental channel numbers. + */ + for (i = 0; i < vm_num; i++) + pvt->vm_idx[i] = i; } else { for (i = 0; i < vm_num; i++) if (pvt->vm_idx[i] >= vm_num || @@ -604,13 +609,6 @@ static int mr75203_probe(struct platform_device *pdev) } } - /* - * Incase intel,vm-map property is not defined, we assume - * incremental channel numbers. - */ - for (i = num; i < vm_num; i++) - pvt->vm_idx[i] = i; - in_config = devm_kcalloc(dev, num + 1, sizeof(*in_config), GFP_KERNEL); if (!in_config) From a02267ebb247ba3c6d7909b03c07b55ae7234415 Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 8 Sep 2022 15:24:31 +0000 Subject: [PATCH 217/228] hwmon: (mr75203) update pvt->v_num and vm_num to the actual number of used sensors [ Upstream commit bb9195bd6664d94d71647631593e09f705ff5edd ] This issue is relevant when "intel,vm-map" is set in device-tree, and defines a lower number of VMs than actually supported. This change is needed for all places that use pvt->v_num or vm_num later on in the code. Fixes: 9d823351a337 ("hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller") Signed-off-by: Eliav Farber Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220908152449.35457-4-farbere@amazon.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/mr75203.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 36cbc86033ce9..6e6aa61ea632b 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -605,6 +605,8 @@ static int mr75203_probe(struct platform_device *pdev) if (pvt->vm_idx[i] >= vm_num || pvt->vm_idx[i] == 0xff) { num = i; + pvt->v_num = i; + vm_num = i; break; } } From 948b7beb0073edee3045dfe7e7b9077083b57496 Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 8 Sep 2022 15:24:32 +0000 Subject: [PATCH 218/228] hwmon: (mr75203) fix voltage equation for negative source input [ Upstream commit 227a3a2fc31d8e4bb9c88d4804e19530af245b1b ] According to Moortec Embedded Voltage Monitor (MEVM) series 3 data sheet, the minimum input signal is -100mv and maximum input signal is +1000mv. The equation used to convert the digital word to voltage uses mixed types (*val signed and n unsigned), and on 64 bit machines also has different size, since sizeof(u32) = 4 and sizeof(long) = 8. So when measuring a negative input, n will be small enough, such that PVT_N_CONST * n < PVT_R_CONST, and the result of (PVT_N_CONST * n - PVT_R_CONST) will overflow to a very big positive 32 bit number. Then when storing the result in *val it will be the same value just in 64 bit (instead of it representing a negative number which will what happen when sizeof(long) = 4). When -1023 <= (PVT_N_CONST * n - PVT_R_CONST) <= -1 dividing the number by 1024 should result of in 0, but because ">> 10" is used, and the sign bit is used to fill the vacated bit positions, it results in -1 (0xf...fffff) which is wrong. This change fixes the sign problem and supports negative values by casting n to long and replacing the shift right with div operation. Fixes: 9d823351a337 ("hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller") Signed-off-by: Eliav Farber Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220908152449.35457-5-farbere@amazon.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/mr75203.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 6e6aa61ea632b..630d596d4317f 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -201,8 +201,18 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) return ret; n &= SAMPLE_DATA_MSK; - /* Convert the N bitstream count into voltage */ - *val = (PVT_N_CONST * n - PVT_R_CONST) >> PVT_CONV_BITS; + /* + * Convert the N bitstream count into voltage. + * To support negative voltage calculation for 64bit machines + * n must be cast to long, since n and *val differ both in + * signedness and in size. + * Division is used instead of right shift, because for signed + * numbers, the sign bit is used to fill the vacated bit + * positions, and if the number is negative, 1 is used. + * BIT(x) may not be used instead of (1 << x) because it's + * unsigned. + */ + *val = (PVT_N_CONST * (long)n - PVT_R_CONST) / (1 << PVT_CONV_BITS); return 0; default: From 5e0fddad71003267d3356be66e307de2571164c7 Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 8 Sep 2022 15:24:33 +0000 Subject: [PATCH 219/228] hwmon: (mr75203) fix multi-channel voltage reading [ Upstream commit 91a9e063cdcfca8fe642b078d6fae4ce49187975 ] Fix voltage allocation and reading to support all channels in all VMs. Prior to this change allocation and reading were done only for the first channel in each VM. This change counts the total number of channels for allocation, and takes into account the channel offset when reading the sample data register. Fixes: 9d823351a337 ("hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller") Signed-off-by: Eliav Farber Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220908152449.35457-6-farbere@amazon.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/mr75203.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 630d596d4317f..e62fae1491c85 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -68,8 +68,9 @@ /* VM Individual Macro Register */ #define VM_COM_REG_SIZE 0x200 -#define VM_SDIF_DONE(n) (VM_COM_REG_SIZE + 0x34 + 0x200 * (n)) -#define VM_SDIF_DATA(n) (VM_COM_REG_SIZE + 0x40 + 0x200 * (n)) +#define VM_SDIF_DONE(vm) (VM_COM_REG_SIZE + 0x34 + 0x200 * (vm)) +#define VM_SDIF_DATA(vm, ch) \ + (VM_COM_REG_SIZE + 0x40 + 0x200 * (vm) + 0x4 * (ch)) /* SDA Slave Register */ #define IP_CTRL 0x00 @@ -115,6 +116,7 @@ struct pvt_device { u32 t_num; u32 p_num; u32 v_num; + u32 c_num; u32 ip_freq; u8 *vm_idx; }; @@ -178,14 +180,15 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) { struct pvt_device *pvt = dev_get_drvdata(dev); struct regmap *v_map = pvt->v_map; + u8 vm_idx, ch_idx; u32 n, stat; - u8 vm_idx; int ret; - if (channel >= pvt->v_num) + if (channel >= pvt->v_num * pvt->c_num) return -EINVAL; - vm_idx = pvt->vm_idx[channel]; + vm_idx = pvt->vm_idx[channel / pvt->c_num]; + ch_idx = channel % pvt->c_num; switch (attr) { case hwmon_in_input: @@ -196,7 +199,7 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) if (ret) return ret; - ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx), &n); + ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx, ch_idx), &n); if(ret < 0) return ret; @@ -509,8 +512,8 @@ static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt static int mr75203_probe(struct platform_device *pdev) { + u32 ts_num, vm_num, pd_num, ch_num, val, index, i; const struct hwmon_channel_info **pvt_info; - u32 ts_num, vm_num, pd_num, val, index, i; struct device *dev = &pdev->dev; u32 *temp_config, *in_config; struct device *hwmon_dev; @@ -551,9 +554,11 @@ static int mr75203_probe(struct platform_device *pdev) ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT; pd_num = (val & PD_NUM_MSK) >> PD_NUM_SFT; vm_num = (val & VM_NUM_MSK) >> VM_NUM_SFT; + ch_num = (val & CH_NUM_MSK) >> CH_NUM_SFT; pvt->t_num = ts_num; pvt->p_num = pd_num; pvt->v_num = vm_num; + pvt->c_num = ch_num; val = 0; if (ts_num) val++; @@ -590,7 +595,7 @@ static int mr75203_probe(struct platform_device *pdev) } if (vm_num) { - u32 num = vm_num; + u32 total_ch; ret = pvt_get_regmap(pdev, "vm", pvt); if (ret) @@ -614,20 +619,20 @@ static int mr75203_probe(struct platform_device *pdev) for (i = 0; i < vm_num; i++) if (pvt->vm_idx[i] >= vm_num || pvt->vm_idx[i] == 0xff) { - num = i; pvt->v_num = i; vm_num = i; break; } } - in_config = devm_kcalloc(dev, num + 1, + total_ch = ch_num * vm_num; + in_config = devm_kcalloc(dev, total_ch + 1, sizeof(*in_config), GFP_KERNEL); if (!in_config) return -ENOMEM; - memset32(in_config, HWMON_I_INPUT, num); - in_config[num] = 0; + memset32(in_config, HWMON_I_INPUT, total_ch); + in_config[total_ch] = 0; pvt_in.config = in_config; pvt_info[index++] = &pvt_in; From 7aa57d869e4a5861df4f5171d9b92f4678215536 Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 8 Sep 2022 15:24:34 +0000 Subject: [PATCH 220/228] hwmon: (mr75203) enable polling for all VM channels [ Upstream commit e43212e0f55dc2d6b15d6c174cc0a64b25fab5e7 ] Configure ip-polling register to enable polling for all voltage monitor channels. This enables reading the voltage values for all inputs other than just input 0. Fixes: 9d823351a337 ("hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller") Signed-off-by: Eliav Farber Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220908152449.35457-7-farbere@amazon.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/mr75203.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index e62fae1491c85..05da83841536f 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -398,6 +398,19 @@ static int pvt_init(struct pvt_device *pvt) if (ret) return ret; + val = (BIT(pvt->c_num) - 1) | VM_CH_INIT | + IP_POLL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if (ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + val = CFG1_VOL_MEAS_MODE | CFG1_PARALLEL_OUT | CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; From a8a007c5b10fc650f1159fa57016ce737f7ec600 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 12 Sep 2022 07:07:56 -0400 Subject: [PATCH 221/228] Revert "arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags"" This reverts commit add4bc9281e8704e5ab15616b429576c84f453a2. On Mon, Sep 12, 2022 at 10:52:45AM +0100, Catalin Marinas wrote: >I missed this (holidays) and it looks like it's in stable already. On >its own it will likely break kasan_hw if used together with user-space >MTE as this change relies on two previous commits: > >70c248aca9e7 ("mm: kasan: Skip unpoisoning of user pages") >6d05141a3930 ("mm: kasan: Skip page unpoisoning only if __GFP_SKIP_KASAN_UNPOISON") > >The reason I did not cc stable is that there are other dependencies in >this area. The potential issues without the above commits were rather >theoretical, so take these patches rather as clean-ups/refactoring than >fixes. Signed-off-by: Sasha Levin --- arch/arm64/kernel/hibernate.c | 5 +++++ arch/arm64/kernel/mte.c | 9 +++++++++ arch/arm64/mm/copypage.c | 9 +++++++++ arch/arm64/mm/mteswap.c | 9 +++++++++ 4 files changed, 32 insertions(+) diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index db93ce2b0113b..46a0b4d6e2519 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -326,6 +326,11 @@ static void swsusp_mte_restore_tags(void) unsigned long pfn = xa_state.xa_index; struct page *page = pfn_to_online_page(pfn); + /* + * It is not required to invoke page_kasan_tag_reset(page) + * at this point since the tags stored in page->flags are + * already restored. + */ mte_restore_page_tags(page_address(page), tags); mte_free_tag_storage(tags); diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c index 10207e3e5ae20..7c1c82c8115cc 100644 --- a/arch/arm64/kernel/mte.c +++ b/arch/arm64/kernel/mte.c @@ -44,6 +44,15 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte, if (!pte_is_tagged) return; + page_kasan_tag_reset(page); + /* + * We need smp_wmb() in between setting the flags and clearing the + * tags because if another thread reads page->flags and builds a + * tagged address out of it, there is an actual dependency to the + * memory access, but on the current thread we do not guarantee that + * the new page->flags are visible before the tags were updated. + */ + smp_wmb(); mte_clear_page_tags(page_address(page)); } diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index 24913271e898c..0dea80bf6de46 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -23,6 +23,15 @@ void copy_highpage(struct page *to, struct page *from) if (system_supports_mte() && test_bit(PG_mte_tagged, &from->flags)) { set_bit(PG_mte_tagged, &to->flags); + page_kasan_tag_reset(to); + /* + * We need smp_wmb() in between setting the flags and clearing the + * tags because if another thread reads page->flags and builds a + * tagged address out of it, there is an actual dependency to the + * memory access, but on the current thread we do not guarantee that + * the new page->flags are visible before the tags were updated. + */ + smp_wmb(); mte_copy_page_tags(kto, kfrom); } } diff --git a/arch/arm64/mm/mteswap.c b/arch/arm64/mm/mteswap.c index c52c1847079c1..7c4ef56265ee1 100644 --- a/arch/arm64/mm/mteswap.c +++ b/arch/arm64/mm/mteswap.c @@ -53,6 +53,15 @@ bool mte_restore_tags(swp_entry_t entry, struct page *page) if (!tags) return false; + page_kasan_tag_reset(page); + /* + * We need smp_wmb() in between setting the flags and clearing the + * tags because if another thread reads page->flags and builds a + * tagged address out of it, there is an actual dependency to the + * memory access, but on the current thread we do not guarantee that + * the new page->flags are visible before the tags were updated. + */ + smp_wmb(); mte_restore_page_tags(page_address(page), tags); return true; From f9e792035a0b6882d895f29de83af1ee67d4b7a8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Sep 2022 15:22:55 +0100 Subject: [PATCH 222/228] arm64/bti: Disable in kernel BTI when cross section thunks are broken commit c0a454b9044fdc99486853aa424e5b3be2107078 upstream. GCC does not insert a `bti c` instruction at the beginning of a function when it believes that all callers reach the function through a direct branch[1]. Unfortunately the logic it uses to determine this is not sufficiently robust, for example not taking account of functions being placed in different sections which may be loaded separately, so we may still see thunks being generated to these functions. If that happens, the first instruction in the callee function will result in a Branch Target Exception due to the missing landing pad. While this has currently only been observed in the case of modules having their main code loaded sufficiently far from their init section to require thunks it could potentially happen for other cases so the safest thing is to disable BTI for the kernel when building with an affected toolchain. [1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671 Reported-by: D Scott Phillips [Bits of the commit message are lifted from his report & workaround] Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20220905142255.591990-1-broonie@kernel.org Cc: # v5.10+ Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9d80c783142f9..42f135e2176b4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1626,6 +1626,8 @@ config ARM64_BTI_KERNEL depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697 depends on !CC_IS_GCC || GCC_VERSION >= 100100 + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671 + depends on !CC_IS_GCC # https://github.com/llvm/llvm-project/commit/a88c722e687e6780dcd6a58718350dc76fcc4cc9 depends on !CC_IS_CLANG || CLANG_VERSION >= 120000 depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS) From 4740910867eaca136c1f322f8fab0234657714ea Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 23 Aug 2022 14:15:55 +0800 Subject: [PATCH 223/228] iommu/vt-d: Correctly calculate sagaw value of IOMMU commit 53fc7ad6edf210b497230ce74b61b322a202470c upstream. The Intel IOMMU driver possibly selects between the first-level and the second-level translation tables for DMA address translation. However, the levels of page-table walks for the 4KB base page size are calculated from the SAGAW field of the capability register, which is only valid for the second-level page table. This causes the IOMMU driver to stop working if the hardware (or the emulated IOMMU) advertises only first-level translation capability and reports the SAGAW field as 0. This solves the above problem by considering both the first level and the second level when calculating the supported page table levels. Fixes: b802d070a52a1 ("iommu/vt-d: Use iova over first level") Cc: stable@vger.kernel.org Signed-off-by: Lu Baolu Link: https://lore.kernel.org/r/20220817023558.3253263-1-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel/iommu.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index a1ffb3d6d9015..bc5444daca9b4 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -542,14 +542,36 @@ static inline int domain_pfn_supported(struct dmar_domain *domain, return !(addr_width < BITS_PER_LONG && pfn >> addr_width); } +/* + * Calculate the Supported Adjusted Guest Address Widths of an IOMMU. + * Refer to 11.4.2 of the VT-d spec for the encoding of each bit of + * the returned SAGAW. + */ +static unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu) +{ + unsigned long fl_sagaw, sl_sagaw; + + fl_sagaw = BIT(2) | (cap_fl1gp_support(iommu->cap) ? BIT(3) : 0); + sl_sagaw = cap_sagaw(iommu->cap); + + /* Second level only. */ + if (!sm_supported(iommu) || !ecap_flts(iommu->ecap)) + return sl_sagaw; + + /* First level only. */ + if (!ecap_slts(iommu->ecap)) + return fl_sagaw; + + return fl_sagaw & sl_sagaw; +} + static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw) { unsigned long sagaw; int agaw; - sagaw = cap_sagaw(iommu->cap); - for (agaw = width_to_agaw(max_gaw); - agaw >= 0; agaw--) { + sagaw = __iommu_calculate_sagaw(iommu); + for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) { if (test_bit(agaw, &sagaw)) break; } From e084c6ab37d2bbd2fca0e993ffe0a308fe407f6c Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Fri, 19 Aug 2022 11:30:50 +0100 Subject: [PATCH 224/228] arm64: errata: add detection for AMEVCNTR01 incrementing incorrectly commit e89d120c4b720e232cc6a94f0fcbd59c15d41489 upstream. The AMU counter AMEVCNTR01 (constant counter) should increment at the same rate as the system counter. On affected Cortex-A510 cores, AMEVCNTR01 increments incorrectly giving a significantly higher output value. This results in inaccurate task scheduler utilization tracking and incorrect feedback on CPU frequency. Work around this problem by returning 0 when reading the affected counter in key locations that results in disabling all users of this counter from using it either for frequency invariance or as FFH reference counter. This effect is the same to firmware disabling affected counters. Details on how the two features are affected by this erratum: - AMU counters will not be used for frequency invariance for affected CPUs and CPUs in the same cpufreq policy. AMUs can still be used for frequency invariance for unaffected CPUs in the system. Although unlikely, if no alternative method can be found to support frequency invariance for affected CPUs (cpufreq based or solution based on platform counters) frequency invariance will be disabled. Please check the chapter on frequency invariance at Documentation/scheduler/sched-capacity.rst for details of its effect. - Given that FFH can be used to fetch either the core or constant counter values, restrictions are lifted regarding any of these counters returning a valid (!0) value. Therefore FFH is considered supported if there is a least one CPU that support AMUs, independent of any counters being disabled or affected by this erratum. Clarifying comments are now added to the cpc_ffh_supported(), cpu_read_constcnt() and cpu_read_corecnt() functions. The above is achieved through adding a new erratum: ARM64_ERRATUM_2457168. Signed-off-by: Ionela Voinescu Reviewed-by: Catalin Marinas Cc: Catalin Marinas Cc: Will Deacon Cc: James Morse Link: https://lore.kernel.org/r/20220819103050.24211-1-ionela.voinescu@arm.com Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- Documentation/arm64/silicon-errata.rst | 2 ++ arch/arm64/Kconfig | 17 ++++++++++++++ arch/arm64/kernel/cpu_errata.c | 9 ++++++++ arch/arm64/kernel/cpufeature.c | 5 +++- arch/arm64/kernel/topology.c | 32 ++++++++++++++++++++++++-- arch/arm64/tools/cpucaps | 1 + 6 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst index 46644736e5835..663001f697733 100644 --- a/Documentation/arm64/silicon-errata.rst +++ b/Documentation/arm64/silicon-errata.rst @@ -94,6 +94,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A510 | #2441009 | ARM64_ERRATUM_2441009 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A510 | #2457168 | ARM64_ERRATUM_2457168 | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N1 | #1349291 | N/A | diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 42f135e2176b4..24cce3b9ff1a7 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -683,6 +683,23 @@ config ARM64_ERRATUM_2441009 If unsure, say Y. +config ARM64_ERRATUM_2457168 + bool "Cortex-A510: 2457168: workaround for AMEVCNTR01 incrementing incorrectly" + depends on ARM64_AMU_EXTN + default y + help + This option adds the workaround for ARM Cortex-A510 erratum 2457168. + + The AMU counter AMEVCNTR01 (constant counter) should increment at the same rate + as the system counter. On affected Cortex-A510 cores AMEVCNTR01 increments + incorrectly giving a significantly higher output value. + + Work around this problem by returning 0 when reading the affected counter in + key locations that results in disabling all users of this counter. This effect + is the same to firmware disabling affected counters. + + If unsure, say Y. + config CAVIUM_ERRATUM_22375 bool "Cavium erratum 22375, 24313" default y diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 23c57e0a7fd14..25c495f58f67a 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -550,6 +550,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .capability = ARM64_WORKAROUND_NVIDIA_CARMEL_CNP, ERRATA_MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL), }, +#endif +#ifdef CONFIG_ARM64_ERRATUM_2457168 + { + .desc = "ARM erratum 2457168", + .capability = ARM64_WORKAROUND_2457168, + .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE, + /* Cortex-A510 r0p0-r1p1 */ + CAP_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1) + }, #endif { } diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 474aa55c2f680..3e52a9e8b50be 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1736,7 +1736,10 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap) pr_info("detected CPU%d: Activity Monitors Unit (AMU)\n", smp_processor_id()); cpumask_set_cpu(smp_processor_id(), &amu_cpus); - update_freq_counters_refs(); + + /* 0 reference values signal broken/disabled counters */ + if (!this_cpu_has_cap(ARM64_WORKAROUND_2457168)) + update_freq_counters_refs(); } } diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 4dd14a6620c17..acf67ef4c505d 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -308,12 +308,25 @@ core_initcall(init_amu_fie); static void cpu_read_corecnt(void *val) { + /* + * A value of 0 can be returned if the current CPU does not support AMUs + * or if the counter is disabled for this CPU. A return value of 0 at + * counter read is properly handled as an error case by the users of the + * counter. + */ *(u64 *)val = read_corecnt(); } static void cpu_read_constcnt(void *val) { - *(u64 *)val = read_constcnt(); + /* + * Return 0 if the current CPU is affected by erratum 2457168. A value + * of 0 is also returned if the current CPU does not support AMUs or if + * the counter is disabled. A return value of 0 at counter read is + * properly handled as an error case by the users of the counter. + */ + *(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_2457168) ? + 0UL : read_constcnt(); } static inline @@ -340,7 +353,22 @@ int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val) */ bool cpc_ffh_supported(void) { - return freq_counters_valid(get_cpu_with_amu_feat()); + int cpu = get_cpu_with_amu_feat(); + + /* + * FFH is considered supported if there is at least one present CPU that + * supports AMUs. Using FFH to read core and reference counters for CPUs + * that do not support AMUs, have counters disabled or that are affected + * by errata, will result in a return value of 0. + * + * This is done to allow any enabled and valid counters to be read + * through FFH, knowing that potentially returning 0 as counter value is + * properly handled by the users of these counters. + */ + if ((cpu >= nr_cpu_ids) || !cpumask_test_cpu(cpu, cpu_present_mask)) + return false; + + return true; } int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val) diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index b71c6cbb23095..cfaffd3c82890 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -54,6 +54,7 @@ WORKAROUND_1418040 WORKAROUND_1463225 WORKAROUND_1508412 WORKAROUND_1542419 +WORKAROUND_2457168 WORKAROUND_CAVIUM_23154 WORKAROUND_CAVIUM_27456 WORKAROUND_CAVIUM_30115 From 590b4f10e3a40c098ee0fe1c332dbff57d9ec24f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 20 Oct 2021 14:39:42 +0200 Subject: [PATCH 225/228] drm/bridge: display-connector: implement bus fmts callbacks commit 7cd70656d1285b79c001f041a017fcfee4292ff9 upstream. Since this bridge is tied to the connector, it acts like a passthrough, so concerning the output & input bus formats, either pass the bus formats from the previous bridge or return fallback data like done in the bridge function: drm_atomic_bridge_chain_select_bus_fmts() & select_bus_fmt_recursive. This permits avoiding skipping the negociation if the remaining bridge chain has all the bits in place. Without this bus fmt negociation breaks on drm/meson HDMI pipeline when attaching dw-hdmi with DRM_BRIDGE_ATTACH_NO_CONNECTOR, because the last bridge of the display-connector doesn't implement buf fmt callbacks and MEDIA_BUS_FMT_FIXED is used leading to select an unsupported default bus format from dw-hdmi. Signed-off-by: Neil Armstrong Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20211020123947.2585572-2-narmstrong@baylibre.com Cc: Stefan Agner Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/bridge/display-connector.c | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 847a0dce7f1d3..d24f5b90feabf 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -87,10 +88,95 @@ static struct edid *display_connector_get_edid(struct drm_bridge *bridge, return drm_get_edid(connector, conn->bridge.ddc); } +/* + * Since this bridge is tied to the connector, it acts like a passthrough, + * so concerning the output bus formats, either pass the bus formats from the + * previous bridge or return fallback data like done in the bridge function: + * drm_atomic_bridge_chain_select_bus_fmts(). + * This supports negotiation if the bridge chain has all bits in place. + */ +static u32 *display_connector_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge_state *prev_bridge_state; + + if (!prev_bridge || !prev_bridge->funcs->atomic_get_output_bus_fmts) { + struct drm_connector *conn = conn_state->connector; + u32 *out_bus_fmts; + + *num_output_fmts = 1; + out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); + if (!out_bus_fmts) + return NULL; + + if (conn->display_info.num_bus_formats && + conn->display_info.bus_formats) + out_bus_fmts[0] = conn->display_info.bus_formats[0]; + else + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + + return out_bus_fmts; + } + + prev_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + prev_bridge); + + return prev_bridge->funcs->atomic_get_output_bus_fmts(prev_bridge, prev_bridge_state, + crtc_state, conn_state, + num_output_fmts); +} + +/* + * Since this bridge is tied to the connector, it acts like a passthrough, + * so concerning the input bus formats, either pass the bus formats from the + * previous bridge or MEDIA_BUS_FMT_FIXED (like select_bus_fmt_recursive()) + * when atomic_get_input_bus_fmts is not supported. + * This supports negotiation if the bridge chain has all bits in place. + */ +static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge_state *prev_bridge_state; + + if (!prev_bridge || !prev_bridge->funcs->atomic_get_input_bus_fmts) { + u32 *in_bus_fmts; + + *num_input_fmts = 1; + in_bus_fmts = kmalloc(sizeof(*in_bus_fmts), GFP_KERNEL); + if (!in_bus_fmts) + return NULL; + + in_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + + return in_bus_fmts; + } + + prev_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + prev_bridge); + + return prev_bridge->funcs->atomic_get_input_bus_fmts(prev_bridge, prev_bridge_state, + crtc_state, conn_state, output_fmt, + num_input_fmts); +} + static const struct drm_bridge_funcs display_connector_bridge_funcs = { .attach = display_connector_attach, .detect = display_connector_detect, .get_edid = display_connector_get_edid, + .atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts, + .atomic_get_input_bus_fmts = display_connector_get_input_bus_fmts, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, }; static irqreturn_t display_connector_hpd_irq(int irq, void *arg) From 154e72a4b38166b0b28d1f1a8d256ad5ca9ad064 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Jan 2022 09:02:43 -0300 Subject: [PATCH 226/228] perf machine: Use path__join() to compose a path instead of snprintf(dir, '/', filename) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9d5f0c36438eeae7566ca383b2b673179e3cc613 upstream. Its more intention revealing, and if we're interested in the odd cases where this may end up truncating we can do debug checks at one centralized place. Motivation, of all the container builds, fedora rawhide started complaining of: util/machine.c: In function ‘machine__create_modules’: util/machine.c:1419:50: error: ‘%s’ directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=] 1419 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | ^~ In file included from /usr/include/stdio.h:894, from util/branch.h:9, from util/callchain.h:8, from util/machine.c:7: In function ‘snprintf’, inlined from ‘maps__set_modules_path_dir’ at util/machine.c:1419:3, inlined from ‘machine__set_modules_path’ at util/machine.c:1473:9, inlined from ‘machine__create_modules’ at util/machine.c:1519:7: /usr/include/bits/stdio2.h:71:10: note: ‘__builtin___snprintf_chk’ output between 2 and 4352 bytes into a destination of size 4096 There are other places where we should use path__join(), but lets get rid of this one first. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Acked-by: Ian Rogers Link: Link: https://lore.kernel.org/r/YebZKjwgfdOz0lAs@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/machine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 44e40bad0e336..55a041329990c 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -16,6 +16,7 @@ #include "map_symbol.h" #include "branch.h" #include "mem-events.h" +#include "path.h" #include "srcline.h" #include "symbol.h" #include "sort.h" @@ -1407,7 +1408,7 @@ static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, i struct stat st; /*sshfs might return bad dent->d_type, so we have to stat*/ - snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); + path__join(path, sizeof(path), dir_name, dent->d_name); if (stat(path, &st)) continue; From e04b25638aefe4af91ef84aa7d37e3474470b622 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 13 Jan 2022 16:48:51 +0200 Subject: [PATCH 227/228] ARM: at91: ddr: remove CONFIG_SOC_SAMA7 dependency [ Upstream commit dc3005703f8cd893d325081c20b400e08377d9bb ] Remove CONFIG_SOC_SAMA7 dependency to avoid having #ifdef preprocessor directives in driver code (arch/arm/mach-at91/pm.c). This prepares the code for next commits. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20220113144900.906370-2-claudiu.beznea@microchip.com Signed-off-by: Sasha Levin --- include/soc/at91/sama7-ddr.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h index 72d19887ab810..f203f34dba12e 100644 --- a/include/soc/at91/sama7-ddr.h +++ b/include/soc/at91/sama7-ddr.h @@ -11,8 +11,6 @@ #ifndef __SAMA7_DDR_H__ #define __SAMA7_DDR_H__ -#ifdef CONFIG_SOC_SAMA7 - /* DDR3PHY */ #define DDR3PHY_PIR (0x04) /* DDR3PHY PHY Initialization Register */ #define DDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */ @@ -83,6 +81,4 @@ #define UDDRC_PCTRL_3 (0x6A0) /* UDDRC Port 3 Control Register */ #define UDDRC_PCTRL_4 (0x750) /* UDDRC Port 4 Control Register */ -#endif /* CONFIG_SOC_SAMA7 */ - #endif /* __SAMA7_DDR_H__ */ From dd20085f2a88b6cdb12bdcdbd2d7a761c86b184a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 15 Sep 2022 11:30:08 +0200 Subject: [PATCH 228/228] Linux 5.15.68 Link: https://lore.kernel.org/r/20220913140357.323297659@linuxfoundation.org Tested-by: Bagas Sanjaya =20 Tested-by: Sudip Mukherjee Tested-by: Linux Kernel Functional Testing Tested-by: Ron Economos Tested-by: Jon Hunter Tested-by: Guenter Roeck Tested-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 32253ea989217..d6b672375c079 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 15 -SUBLEVEL = 67 +SUBLEVEL = 68 EXTRAVERSION = NAME = Trick or Treat