From: Xiyu Yang xiyuyang19@fudan.edu.cn
[ Upstream commit f62314b1ced25c58b86e044fc951cd6a1ea234cf ]
The reference counting issue happens in the normal path of kfree_at_end(). When kunit_alloc_and_get_resource() is invoked, the function forgets to handle the returned resource object, whose refcount increased inside, causing a refcount leak.
Fix this issue by calling kunit_alloc_resource() instead of kunit_alloc_and_get_resource().
Fixed the following when applying: Shuah Khan skhan@linuxfoundation.org
CHECK: Alignment should match open parenthesis + kunit_alloc_resource(test, NULL, kfree_res_free, GFP_KERNEL, (void *)to_free);
Signed-off-by: Xiyu Yang xiyuyang19@fudan.edu.cn Signed-off-by: Xin Tan tanxin.ctf@gmail.com Reviewed-by: Daniel Latypov dlatypov@google.com Reviewed-by: Brendan Higgins brendanhiggins@google.com Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- lib/kunit/executor_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c index cdbe54b16501..e14a18af573d 100644 --- a/lib/kunit/executor_test.c +++ b/lib/kunit/executor_test.c @@ -116,8 +116,8 @@ static void kfree_at_end(struct kunit *test, const void *to_free) /* kfree() handles NULL already, but avoid allocating a no-op cleanup. */ if (IS_ERR_OR_NULL(to_free)) return; - kunit_alloc_and_get_resource(test, NULL, kfree_res_free, GFP_KERNEL, - (void *)to_free); + kunit_alloc_resource(test, NULL, kfree_res_free, GFP_KERNEL, + (void *)to_free); }
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
From: Rob Clark robdclark@chromium.org
[ Upstream commit f6f59072e821901d96c791864a07d57d8ec8d312 ]
I've seen some crashes in our crash reporting that *look* like multiple threads stomping on each other while communicating with GMU. So wrap all those paths in a lock.
Signed-off-by: Rob Clark robdclark@chromium.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 6 ++++ drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 3 ++ drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 40 +++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index b349692219b7..c95985792076 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -296,6 +296,8 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) u32 val; int request, ack;
+ WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); + if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits)) return -EINVAL;
@@ -337,6 +339,8 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) { int bit;
+ WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); + if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits)) return;
@@ -1478,6 +1482,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) if (!pdev) return -ENODEV;
+ mutex_init(&gmu->lock); + gmu->dev = &pdev->dev;
of_dma_configure(gmu->dev, node, true); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 71dfa60070cc..19c1a0ddee7a 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -44,6 +44,9 @@ struct a6xx_gmu_bo { struct a6xx_gmu { struct device *dev;
+ /* For serializing communication with the GMU: */ + struct mutex lock; + struct msm_gem_address_space *aspace;
void * __iomem mmio; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 183b9f9c1b31..64586eb8cda5 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -859,7 +859,7 @@ static int a6xx_zap_shader_init(struct msm_gpu *gpu) A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ A6XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR)
-static int a6xx_hw_init(struct msm_gpu *gpu) +static int hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); @@ -1107,6 +1107,19 @@ static int a6xx_hw_init(struct msm_gpu *gpu) return ret; }
+static int a6xx_hw_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + int ret; + + mutex_lock(&a6xx_gpu->gmu.lock); + ret = hw_init(gpu); + mutex_unlock(&a6xx_gpu->gmu.lock); + + return ret; +} + static void a6xx_dump(struct msm_gpu *gpu) { DRM_DEV_INFO(&gpu->pdev->dev, "status: %08x\n", @@ -1481,7 +1494,9 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)
trace_msm_gpu_resume(0);
+ mutex_lock(&a6xx_gpu->gmu.lock); ret = a6xx_gmu_resume(a6xx_gpu); + mutex_unlock(&a6xx_gpu->gmu.lock); if (ret) return ret;
@@ -1504,7 +1519,9 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
devfreq_suspend_device(gpu->devfreq.devfreq);
+ mutex_lock(&a6xx_gpu->gmu.lock); ret = a6xx_gmu_stop(a6xx_gpu); + mutex_unlock(&a6xx_gpu->gmu.lock); if (ret) return ret;
@@ -1519,18 +1536,19 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - static DEFINE_MUTEX(perfcounter_oob);
- mutex_lock(&perfcounter_oob); + mutex_lock(&a6xx_gpu->gmu.lock);
/* Force the GPU power on so we can read this register */ a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
*value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO, - REG_A6XX_CP_ALWAYS_ON_COUNTER_HI); + REG_A6XX_CP_ALWAYS_ON_COUNTER_HI);
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); - mutex_unlock(&perfcounter_oob); + + mutex_unlock(&a6xx_gpu->gmu.lock); + return 0; }
@@ -1594,6 +1612,16 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) return (unsigned long)busy_time; }
+void a6xx_gpu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + + mutex_lock(&a6xx_gpu->gmu.lock); + a6xx_gmu_set_freq(gpu, opp); + mutex_unlock(&a6xx_gpu->gmu.lock); +} + static struct msm_gem_address_space * a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) { @@ -1740,7 +1768,7 @@ static const struct adreno_gpu_funcs funcs = { #endif .gpu_busy = a6xx_gpu_busy, .gpu_get_freq = a6xx_gmu_get_freq, - .gpu_set_freq = a6xx_gmu_set_freq, + .gpu_set_freq = a6xx_gpu_set_freq, #if defined(CONFIG_DRM_MSM_GPU_STATE) .gpu_state_get = a6xx_gpu_state_get, .gpu_state_put = a6xx_gpu_state_put,
From: Brendan Higgins brendanhiggins@google.com
[ Upstream commit 554afc3b9797511e3245864e32aebeb6abbab1e3 ]
KUnit and structleak don't play nice, so add a makefile variable for enabling structleak when it complains.
Co-developed-by: Kees Cook keescook@chromium.org Signed-off-by: Kees Cook keescook@chromium.org Signed-off-by: Brendan Higgins brendanhiggins@google.com Reviewed-by: David Gow davidgow@google.com Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- scripts/Makefile.gcc-plugins | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 952e46876329..4aad28480035 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -19,6 +19,10 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \ += -fplugin-arg-structleak_plugin-byref gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \ += -fplugin-arg-structleak_plugin-byref-all +ifdef CONFIG_GCC_PLUGIN_STRUCTLEAK + DISABLE_STRUCTLEAK_PLUGIN += -fplugin-arg-structleak_plugin-disable +endif +export DISABLE_STRUCTLEAK_PLUGIN gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ += -DSTRUCTLEAK_PLUGIN
From: Brendan Higgins brendanhiggins@google.com
[ Upstream commit 2326f3cdba1d105b68cc1295e78f17ae8faa5a76 ]
The structleak plugin causes the stack frame size to grow immensely when used with KUnit:
../drivers/iio/test/iio-test-format.c: In function ‘iio_test_iio_format_value_fixedpoint’: ../drivers/iio/test/iio-test-format.c:98:1: warning: the frame size of 2336 bytes is larger than 2048 bytes [-Wframe-larger-than=]
Turn it off in this file.
Signed-off-by: Brendan Higgins brendanhiggins@google.com Suggested-by: Arnd Bergmann arnd@arndb.de Reviewed-by: Kees Cook keescook@chromium.org Acked-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/iio/test/Makefile | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile index f1099b495301..467519a2027e 100644 --- a/drivers/iio/test/Makefile +++ b/drivers/iio/test/Makefile @@ -5,3 +5,4 @@
# Keep in alphabetical order obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o +CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN)
From: Brendan Higgins brendanhiggins@google.com
[ Upstream commit 6a1e2d93d55b000962b82b9a080006446150b022 ]
The structleak plugin causes the stack frame size to grow immensely when used with KUnit:
../drivers/base/test/property-entry-test.c:492:1: warning: the frame size of 2832 bytes is larger than 2048 bytes [-Wframe-larger-than=] ../drivers/base/test/property-entry-test.c:322:1: warning: the frame size of 2080 bytes is larger than 2048 bytes [-Wframe-larger-than=] ../drivers/base/test/property-entry-test.c:250:1: warning: the frame size of 4976 bytes is larger than 2048 bytes [-Wframe-larger-than=] ../drivers/base/test/property-entry-test.c:115:1: warning: the frame size of 3280 bytes is larger than 2048 bytes [-Wframe-larger-than=]
Turn it off in this file.
Signed-off-by: Brendan Higgins brendanhiggins@google.com Suggested-by: Arnd Bergmann arnd@arndb.de Reviewed-by: Kees Cook keescook@chromium.org Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/base/test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/base/test/Makefile b/drivers/base/test/Makefile index 64b2f3d744d5..7f76fee6f989 100644 --- a/drivers/base/test/Makefile +++ b/drivers/base/test/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o
obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o -CFLAGS_REMOVE_property-entry-test.o += -fplugin-arg-structleak_plugin-byref -fplugin-arg-structleak_plugin-byref-all +CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
From: Brendan Higgins brendanhiggins@google.com
[ Upstream commit 33d4951e021bb67ebd6bdb01f3d437c0f45b3c0c ]
The structleak plugin causes the stack frame size to grow immensely when used with KUnit:
drivers/thunderbolt/test.c:1529:1: error: the frame size of 1176 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]
Turn it off in this file.
Linus already split up tests in this file, so this change *should* be redundant now.
Signed-off-by: Brendan Higgins brendanhiggins@google.com Suggested-by: Arnd Bergmann arnd@arndb.de Acked-by: Mika Westerberg mika.westerberg@linux.intel.com Reviewed-by: Kees Cook keescook@chromium.org Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/thunderbolt/Makefile | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index da19d7987d00..78fd365893c1 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -7,6 +7,7 @@ thunderbolt-objs += usb4_port.o nvm.o retimer.o quirks.o thunderbolt-${CONFIG_ACPI} += acpi.o thunderbolt-$(CONFIG_DEBUG_FS) += debugfs.o thunderbolt-${CONFIG_USB4_KUNIT_TEST} += test.o +CFLAGS_test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
thunderbolt_dma_test-${CONFIG_USB4_DMA_TEST} += dma_test.o obj-$(CONFIG_USB4_DMA_TEST) += thunderbolt_dma_test.o
From: Arnd Bergmann arnd@arndb.de
[ Upstream commit a8cf90332ae3e2b53813a146a99261b6a5e16a73 ]
The structleak plugin causes the stack frame size to grow immensely:
lib/bitfield_kunit.c: In function 'test_bitfields_constants': lib/bitfield_kunit.c:93:1: error: the frame size of 7440 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
Turn it off in this file.
Signed-off-by: Arnd Bergmann arnd@arndb.de Signed-off-by: Brendan Higgins brendanhiggins@google.com Reviewed-by: Kees Cook keescook@chromium.org Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/Makefile b/lib/Makefile index 5efd1b435a37..a841be5244ac 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -351,7 +351,7 @@ obj-$(CONFIG_OBJAGG) += objagg.o obj-$(CONFIG_PLDMFW) += pldmfw/
# KUnit tests -CFLAGS_bitfield_kunit.o := $(call cc-option,-Wframe-larger-than=10240) +CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN) obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
From: Michael Forney mforney@mforney.org
[ Upstream commit b46179d6bb3182c020f2bf9bb4df6ba5463b0495 ]
Otherwise, if these fail we end up with garbage data in the .rela.orc_unwind_ip section, leading to errors like
ld: fs/squashfs/namei.o: bad reloc symbol index (0x7f16 >= 0x12) for offset 0x7f16d5c82cc8 in section `.orc_unwind_ip'
Signed-off-by: Michael Forney mforney@mforney.org Reviewed-by: Miroslav Benes mbenes@suse.cz Signed-off-by: Josh Poimboeuf jpoimboe@redhat.com Link: https://lore.kernel.org/r/20210509000103.11008-1-mforney@mforney.org Signed-off-by: Sasha Levin sashal@kernel.org --- tools/objtool/elf.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 8676c7598728..6cf4c0f11906 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -1003,7 +1003,10 @@ static int elf_rebuild_rel_reloc_section(struct section *sec, int nr) list_for_each_entry(reloc, &sec->reloc_list, list) { reloc->rel.r_offset = reloc->offset; reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - gelf_update_rel(sec->data, idx, &reloc->rel); + if (!gelf_update_rel(sec->data, idx, &reloc->rel)) { + WARN_ELF("gelf_update_rel"); + return -1; + } idx++; }
@@ -1035,7 +1038,10 @@ static int elf_rebuild_rela_reloc_section(struct section *sec, int nr) reloc->rela.r_offset = reloc->offset; reloc->rela.r_addend = reloc->addend; reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - gelf_update_rela(sec->data, idx, &reloc->rela); + if (!gelf_update_rela(sec->data, idx, &reloc->rela)) { + WARN_ELF("gelf_update_rela"); + return -1; + } idx++; }
From: Michael Forney mforney@mforney.org
[ Upstream commit 86e1e054e0d2105cf32b0266cf1a64e6c26424f7 ]
The libelf implementation from elftoolchain has a safety check in gelf_update_rel[a] to check that the data corresponds to a section that has type SHT_REL[A] [0]. If the relocation is updated before the section header is updated with the proper type, this check fails.
To fix this, update the section header first, before the relocations. Previously, the section size was calculated in elf_rebuild_reloc_section by counting the number of entries in the reloc_list. However, we now need the size during elf_write so instead keep a running total and add to it for every new relocation.
[0] https://sourceforge.net/p/elftoolchain/mailman/elftoolchain-developers/threa...
Signed-off-by: Michael Forney mforney@mforney.org Reviewed-by: Miroslav Benes mbenes@suse.cz Signed-off-by: Josh Poimboeuf jpoimboe@redhat.com Link: https://lore.kernel.org/r/20210509000103.11008-2-mforney@mforney.org Signed-off-by: Sasha Levin sashal@kernel.org --- tools/objtool/elf.c | 46 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 29 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 6cf4c0f11906..a9c2bebd7576 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -509,6 +509,7 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, list_add_tail(&reloc->list, &sec->reloc->reloc_list); elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
+ sec->reloc->sh.sh_size += sec->reloc->sh.sh_entsize; sec->reloc->changed = true;
return 0; @@ -979,26 +980,23 @@ static struct section *elf_create_reloc_section(struct elf *elf, } }
-static int elf_rebuild_rel_reloc_section(struct section *sec, int nr) +static int elf_rebuild_rel_reloc_section(struct section *sec) { struct reloc *reloc; - int idx = 0, size; + int idx = 0; void *buf;
/* Allocate a buffer for relocations */ - size = nr * sizeof(GElf_Rel); - buf = malloc(size); + buf = malloc(sec->sh.sh_size); if (!buf) { perror("malloc"); return -1; }
sec->data->d_buf = buf; - sec->data->d_size = size; + sec->data->d_size = sec->sh.sh_size; sec->data->d_type = ELF_T_REL;
- sec->sh.sh_size = size; - idx = 0; list_for_each_entry(reloc, &sec->reloc_list, list) { reloc->rel.r_offset = reloc->offset; @@ -1013,26 +1011,23 @@ static int elf_rebuild_rel_reloc_section(struct section *sec, int nr) return 0; }
-static int elf_rebuild_rela_reloc_section(struct section *sec, int nr) +static int elf_rebuild_rela_reloc_section(struct section *sec) { struct reloc *reloc; - int idx = 0, size; + int idx = 0; void *buf;
/* Allocate a buffer for relocations with addends */ - size = nr * sizeof(GElf_Rela); - buf = malloc(size); + buf = malloc(sec->sh.sh_size); if (!buf) { perror("malloc"); return -1; }
sec->data->d_buf = buf; - sec->data->d_size = size; + sec->data->d_size = sec->sh.sh_size; sec->data->d_type = ELF_T_RELA;
- sec->sh.sh_size = size; - idx = 0; list_for_each_entry(reloc, &sec->reloc_list, list) { reloc->rela.r_offset = reloc->offset; @@ -1050,16 +1045,9 @@ static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec) { - struct reloc *reloc; - int nr; - - nr = 0; - list_for_each_entry(reloc, &sec->reloc_list, list) - nr++; - switch (sec->sh.sh_type) { - case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr); - case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr); + case SHT_REL: return elf_rebuild_rel_reloc_section(sec); + case SHT_RELA: return elf_rebuild_rela_reloc_section(sec); default: return -1; } } @@ -1119,12 +1107,6 @@ int elf_write(struct elf *elf) /* Update changed relocation sections and section headers: */ list_for_each_entry(sec, &elf->sections, list) { if (sec->changed) { - if (sec->base && - elf_rebuild_reloc_section(elf, sec)) { - WARN("elf_rebuild_reloc_section"); - return -1; - } - s = elf_getscn(elf->elf, sec->idx); if (!s) { WARN_ELF("elf_getscn"); @@ -1135,6 +1117,12 @@ int elf_write(struct elf *elf) return -1; }
+ if (sec->base && + elf_rebuild_reloc_section(elf, sec)) { + WARN("elf_rebuild_reloc_section"); + return -1; + } + sec->changed = false; elf->changed = true; }
From: Takashi Iwai tiwai@suse.de
[ Upstream commit c0f1886de7e173865f1a0fa7680a1c07954a987f ]
It seems that a few recent AMD systems show the codec configuration errors at the early boot, while loading the driver at a later stage works magically. Although the root cause of the error isn't clear, it's certainly not bad to allow retrying the codec probe in such a case if that helps.
This patch adds the capability for retrying the probe upon codec probe errors on the certain AMD platforms. The probe_work is changed to a delayed work, and at the secondary call, it'll jump to the codec probing.
Note that, not only adding the re-probing, this includes the behavior changes in the codec configuration function. Namely, snd_hda_codec_configure() won't unregister the codec at errors any longer. Instead, its caller, azx_codec_configure() unregisters the codecs with the probe failures *if* any codec has been successfully configured. If all codec probe failed, it doesn't unregister but let it re-probed -- which is the most case we're seeing and this patch tries to improve.
Even if the driver doesn't re-probe or give up, it will go to the "free-all" error path, hence the leftover codecs shall be disabled / deleted in anyway.
BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1190801 Link: https://lore.kernel.org/r/20211006141940.2897-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Sasha Levin sashal@kernel.org --- include/sound/hda_codec.h | 1 + sound/pci/hda/hda_bind.c | 20 +++++++++++--------- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_controller.c | 24 ++++++++++++++++-------- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 29 +++++++++++++++++++++++------ sound/pci/hda/hda_intel.h | 4 +++- 7 files changed, 56 insertions(+), 25 deletions(-)
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 2e8d51937acd..47d2cad21b56 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -225,6 +225,7 @@ struct hda_codec { #endif
/* misc flags */ + unsigned int configured:1; /* codec was configured */ unsigned int in_freeing:1; /* being released */ unsigned int registered:1; /* codec was registered */ unsigned int display_power_control:1; /* needs display power */ diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index e8dee24c309d..50a58fb5ad9c 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -304,29 +304,31 @@ int snd_hda_codec_configure(struct hda_codec *codec) { int err;
+ if (codec->configured) + return 0; + if (is_generic_config(codec)) codec->probe_id = HDA_CODEC_ID_GENERIC; else codec->probe_id = 0;
- err = snd_hdac_device_register(&codec->core); - if (err < 0) - return err; + if (!device_is_registered(&codec->core.dev)) { + err = snd_hdac_device_register(&codec->core); + if (err < 0) + return err; + }
if (!codec->preset) codec_bind_module(codec); if (!codec->preset) { err = codec_bind_generic(codec); if (err < 0) { - codec_err(codec, "Unable to bind the codec\n"); - goto error; + codec_dbg(codec, "Unable to bind the codec\n"); + return err; } }
+ codec->configured = 1; return 0; - - error: - snd_hdac_device_unregister(&codec->core); - return err; } EXPORT_SYMBOL_GPL(snd_hda_codec_configure); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 7a717e151156..8afcce6478cd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -791,6 +791,7 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) snd_array_free(&codec->nids); remove_conn_list(codec); snd_hdac_regmap_exit(&codec->core); + codec->configured = 0; } EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_for_unbind);
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index ca2f2ecd1488..5a49ee4f6ce0 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -25,6 +25,7 @@ #include <sound/core.h> #include <sound/initval.h> #include "hda_controller.h" +#include "hda_local.h"
#define CREATE_TRACE_POINTS #include "hda_controller_trace.h" @@ -1259,17 +1260,24 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); int azx_codec_configure(struct azx *chip) { struct hda_codec *codec, *next; + int success = 0;
- /* use _safe version here since snd_hda_codec_configure() deregisters - * the device upon error and deletes itself from the bus list. - */ - list_for_each_codec_safe(codec, next, &chip->bus) { - snd_hda_codec_configure(codec); + list_for_each_codec(codec, &chip->bus) { + if (!snd_hda_codec_configure(codec)) + success++; }
- if (!azx_bus(chip)->num_codecs) - return -ENODEV; - return 0; + if (success) { + /* unregister failed codecs if any codec has been probed */ + list_for_each_codec_safe(codec, next, &chip->bus) { + if (!codec->configured) { + codec_err(codec, "Unable to configure, disabling\n"); + snd_hdac_device_unregister(&codec->core); + } + } + } + + return success ? 0 : -ENODEV; } EXPORT_SYMBOL_GPL(azx_codec_configure);
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 68f9668788ea..324cba13c7ba 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -41,7 +41,7 @@ /* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -/* 27 unused */ +#define AZX_DCAPS_RETRY_PROBE (1 << 27) /* retry probe if no codec is configured */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0062c18b646a..89f135a6a1f6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -307,7 +307,8 @@ enum { /* quirks for AMD SB */ #define AZX_DCAPS_PRESET_AMD_SB \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_AMD_WORKAROUND |\ - AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME) + AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME |\ + AZX_DCAPS_RETRY_PROBE)
/* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ @@ -1730,7 +1731,7 @@ static void azx_check_snoop_available(struct azx *chip)
static void azx_probe_work(struct work_struct *work) { - struct hda_intel *hda = container_of(work, struct hda_intel, probe_work); + struct hda_intel *hda = container_of(work, struct hda_intel, probe_work.work); azx_probe_continue(&hda->chip); }
@@ -1839,7 +1840,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, }
/* continue probing in work context as may trigger request module */ - INIT_WORK(&hda->probe_work, azx_probe_work); + INIT_DELAYED_WORK(&hda->probe_work, azx_probe_work);
*rchip = chip;
@@ -2170,7 +2171,7 @@ static int azx_probe(struct pci_dev *pci, #endif
if (schedule_probe) - schedule_work(&hda->probe_work); + schedule_delayed_work(&hda->probe_work, 0);
dev++; if (chip->disabled) @@ -2256,6 +2257,11 @@ static int azx_probe_continue(struct azx *chip) int dev = chip->dev_index; int err;
+ if (chip->disabled || hda->init_failed) + return -EIO; + if (hda->probe_retry) + goto probe_retry; + to_hda_bus(bus)->bus_probing = 1; hda->probe_continued = 1;
@@ -2317,10 +2323,20 @@ static int azx_probe_continue(struct azx *chip) #endif } #endif + + probe_retry: if (bus->codec_mask && !(probe_only[dev] & 1)) { err = azx_codec_configure(chip); - if (err < 0) + if (err) { + if ((chip->driver_caps & AZX_DCAPS_RETRY_PROBE) && + ++hda->probe_retry < 60) { + schedule_delayed_work(&hda->probe_work, + msecs_to_jiffies(1000)); + return 0; /* keep things up */ + } + dev_err(chip->card->dev, "Cannot probe codecs, giving up\n"); goto out_free; + } }
err = snd_card_register(chip->card); @@ -2350,6 +2366,7 @@ static int azx_probe_continue(struct azx *chip) display_power(chip, false); complete_all(&hda->probe_wait); to_hda_bus(bus)->bus_probing = 0; + hda->probe_retry = 0; return 0; }
@@ -2375,7 +2392,7 @@ static void azx_remove(struct pci_dev *pci) * device during cancel_work_sync() call. */ device_unlock(&pci->dev); - cancel_work_sync(&hda->probe_work); + cancel_delayed_work_sync(&hda->probe_work); device_lock(&pci->dev);
snd_card_free(card); diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 3fb119f09040..0f39418f9328 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -14,7 +14,7 @@ struct hda_intel {
/* sync probing */ struct completion probe_wait; - struct work_struct probe_work; + struct delayed_work probe_work;
/* card list (for power_save trigger) */ struct list_head list; @@ -30,6 +30,8 @@ struct hda_intel { unsigned int freed:1; /* resources already released */
bool need_i915_power:1; /* the hda controller needs i915 power */ + + int probe_retry; /* being probe-retry */ };
#endif
From: Filipe Manana fdmanana@suse.com
[ Upstream commit 77a5b9e3d14cbce49ceed2766b2003c034c066dc ]
Currently inode_in_dir() ignores errors returned from btrfs_lookup_dir_index_item() and from btrfs_lookup_dir_item(), treating any errors as if the directory entry does not exists in the fs/subvolume tree, which is obviously not correct, as we can get errors such as -EIO when reading extent buffers while searching the fs/subvolume's tree.
Fix that by making inode_in_dir() return the errors and making its only caller, add_inode_ref(), deal with returned errors as well.
Signed-off-by: Filipe Manana fdmanana@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/btrfs/tree-log.c | 47 ++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 7037e5855d2a..529c1c638b7a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -939,9 +939,11 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, }
/* - * helper function to see if a given name and sequence number found - * in an inode back reference are already in a directory and correctly - * point to this inode + * See if a given name and sequence number found in an inode back reference are + * already in a directory and correctly point to this inode. + * + * Returns: < 0 on error, 0 if the directory entry does not exists and 1 if it + * exists. */ static noinline int inode_in_dir(struct btrfs_root *root, struct btrfs_path *path, @@ -950,29 +952,35 @@ static noinline int inode_in_dir(struct btrfs_root *root, { struct btrfs_dir_item *di; struct btrfs_key location; - int match = 0; + int ret = 0;
di = btrfs_lookup_dir_index_item(NULL, root, path, dirid, index, name, name_len, 0); - if (di && !IS_ERR(di)) { + if (IS_ERR(di)) { + if (PTR_ERR(di) != -ENOENT) + ret = PTR_ERR(di); + goto out; + } else if (di) { btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); if (location.objectid != objectid) goto out; - } else + } else { goto out; - btrfs_release_path(path); + }
+ btrfs_release_path(path); di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0); - if (di && !IS_ERR(di)) { - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); - if (location.objectid != objectid) - goto out; - } else + if (IS_ERR(di)) { + ret = PTR_ERR(di); goto out; - match = 1; + } else if (di) { + btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); + if (location.objectid == objectid) + ret = 1; + } out: btrfs_release_path(path); - return match; + return ret; }
/* @@ -1517,10 +1525,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (ret) goto out;
- /* if we already have a perfect match, we're done */ - if (!inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)), - btrfs_ino(BTRFS_I(inode)), ref_index, - name, namelen)) { + ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)), + btrfs_ino(BTRFS_I(inode)), ref_index, + name, namelen); + if (ret < 0) { + goto out; + } else if (ret == 0) { /* * look for a conflicting back reference in the * metadata. if we find one we have to unlink that name @@ -1580,6 +1590,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (ret) goto out; } + /* Else, ret == 1, we already have a perfect match, we're done. */
ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen; kfree(name);
From: Herve Codina herve.codina@bootlin.com
[ Upstream commit 9cb1d19f47fafad7dcf7c8564e633440c946cfd7 ]
dwmac 3.40a is an old ip version that can be found on SPEAr3xx soc.
Signed-off-by: Herve Codina herve.codina@bootlin.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 8 ++++++++ 2 files changed, 9 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index fbfda55b4c52..5e731a72cce8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -71,6 +71,7 @@ static int dwmac_generic_probe(struct platform_device *pdev)
static const struct of_device_id dwmac_generic_match[] = { { .compatible = "st,spear600-gmac"}, + { .compatible = "snps,dwmac-3.40a"}, { .compatible = "snps,dwmac-3.50a"}, { .compatible = "snps,dwmac-3.610"}, { .compatible = "snps,dwmac-3.70a"}, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 62cec9bfcd33..232ac98943cd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -508,6 +508,14 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) plat->pmt = 1; }
+ if (of_device_is_compatible(np, "snps,dwmac-3.40a")) { + plat->has_gmac = 1; + plat->enh_desc = 1; + plat->tx_coe = 1; + plat->bugged_jumbo = 1; + plat->pmt = 1; + } + if (of_device_is_compatible(np, "snps,dwmac-4.00") || of_device_is_compatible(np, "snps,dwmac-4.10a") || of_device_is_compatible(np, "snps,dwmac-4.20a") ||
From: Herve Codina herve.codina@bootlin.com
[ Upstream commit 6636fec29cdf6665bd219564609e8651f6ddc142 ]
On SPEAr3xx, ethernet driver is not compatible with the SPEAr600 one. Indeed, SPEAr3xx uses an earlier version of this IP (v3.40) and needs some driver tuning compare to SPEAr600.
The v3.40 IP support was added to stmmac driver and this patch fixes this issue and use the correct compatible string for SPEAr3xx
Signed-off-by: Herve Codina herve.codina@bootlin.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- arch/arm/boot/dts/spear3xx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index f266b7b03482..cc88ebe7a60c 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -47,7 +47,7 @@ dma@fc400000 { };
gmac: eth@e0800000 { - compatible = "st,spear600-gmac"; + compatible = "snps,dwmac-3.40a"; reg = <0xe0800000 0x8000>; interrupts = <23 22>; interrupt-names = "macirq", "eth_wake_irq";
From: Lin Ma linma@zju.edu.cn
[ Upstream commit 1b1499a817c90fd1ce9453a2c98d2a01cca0e775 ]
The nci_core_conn_close_rsp_packet() function will release the conn_info with given conn_id. However, it needs to set the rf_conn_info to NULL to prevent other routines like nci_rf_intf_activated_ntf_packet() to trigger the UAF.
Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@canonical.com Signed-off-by: Lin Ma linma@zju.edu.cn Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@canonical.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- net/nfc/nci/rsp.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index e9605922a322..49cbc44e075d 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -330,6 +330,8 @@ static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev, ndev->cur_conn_id); if (conn_info) { list_del(&conn_info->list); + if (conn_info == ndev->rf_conn_info) + ndev->rf_conn_info = NULL; devm_kfree(&ndev->nfc_dev->dev, conn_info); } }
From: Xiaolong Huang butterflyhuangxx@gmail.com
[ Upstream commit 1f3e2e97c003f80c4b087092b225c8787ff91e4d ]
The cmtp_add_connection() would add a cmtp session to a controller and run a kernel thread to process cmtp.
__module_get(THIS_MODULE); session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", session->num);
During this process, the kernel thread would call detach_capi_ctr() to detach a register controller. if the controller was not attached yet, detach_capi_ctr() would trigger an array-index-out-bounds bug.
[ 46.866069][ T6479] UBSAN: array-index-out-of-bounds in drivers/isdn/capi/kcapi.c:483:21 [ 46.867196][ T6479] index -1 is out of range for type 'capi_ctr *[32]' [ 46.867982][ T6479] CPU: 1 PID: 6479 Comm: kcmtpd_ctr_0 Not tainted 5.15.0-rc2+ #8 [ 46.869002][ T6479] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 [ 46.870107][ T6479] Call Trace: [ 46.870473][ T6479] dump_stack_lvl+0x57/0x7d [ 46.870974][ T6479] ubsan_epilogue+0x5/0x40 [ 46.871458][ T6479] __ubsan_handle_out_of_bounds.cold+0x43/0x48 [ 46.872135][ T6479] detach_capi_ctr+0x64/0xc0 [ 46.872639][ T6479] cmtp_session+0x5c8/0x5d0 [ 46.873131][ T6479] ? __init_waitqueue_head+0x60/0x60 [ 46.873712][ T6479] ? cmtp_add_msgpart+0x120/0x120 [ 46.874256][ T6479] kthread+0x147/0x170 [ 46.874709][ T6479] ? set_kthread_struct+0x40/0x40 [ 46.875248][ T6479] ret_from_fork+0x1f/0x30 [ 46.875773][ T6479]
Signed-off-by: Xiaolong Huang butterflyhuangxx@gmail.com Acked-by: Arnd Bergmann arnd@arndb.de Link: https://lore.kernel.org/r/20211008065830.305057-1-butterflyhuangxx@gmail.com Signed-off-by: Jakub Kicinski kuba@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/isdn/capi/kcapi.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index cb0afe897162..7313454e403a 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -480,6 +480,11 @@ int detach_capi_ctr(struct capi_ctr *ctr)
ctr_down(ctr, CAPI_CTR_DETACHED);
+ if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) { + err = -EINVAL; + goto unlock_out; + } + if (capi_controller[ctr->cnr - 1] != ctr) { err = -EINVAL; goto unlock_out;
From: Zheyu Ma zheyuma97@gmail.com
[ Upstream commit 6510e80a0b81b5d814e3aea6297ba42f5e76f73c ]
The driver can call card->isac.release() function from an atomic context.
Fix this by calling this function after releasing the lock.
The following log reveals it:
[ 44.168226 ] BUG: sleeping function called from invalid context at kernel/workqueue.c:3018 [ 44.168941 ] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 5475, name: modprobe [ 44.169574 ] INFO: lockdep is turned off. [ 44.169899 ] irq event stamp: 0 [ 44.170160 ] hardirqs last enabled at (0): [<0000000000000000>] 0x0 [ 44.170627 ] hardirqs last disabled at (0): [<ffffffff814209ed>] copy_process+0x132d/0x3e00 [ 44.171240 ] softirqs last enabled at (0): [<ffffffff81420a1a>] copy_process+0x135a/0x3e00 [ 44.171852 ] softirqs last disabled at (0): [<0000000000000000>] 0x0 [ 44.172318 ] Preemption disabled at: [ 44.172320 ] [<ffffffffa009b0a9>] nj_release+0x69/0x500 [netjet] [ 44.174441 ] Call Trace: [ 44.174630 ] dump_stack_lvl+0xa8/0xd1 [ 44.174912 ] dump_stack+0x15/0x17 [ 44.175166 ] ___might_sleep+0x3a2/0x510 [ 44.175459 ] ? nj_release+0x69/0x500 [netjet] [ 44.175791 ] __might_sleep+0x82/0xe0 [ 44.176063 ] ? start_flush_work+0x20/0x7b0 [ 44.176375 ] start_flush_work+0x33/0x7b0 [ 44.176672 ] ? trace_irq_enable_rcuidle+0x85/0x170 [ 44.177034 ] ? kasan_quarantine_put+0xaa/0x1f0 [ 44.177372 ] ? kasan_quarantine_put+0xaa/0x1f0 [ 44.177711 ] __flush_work+0x11a/0x1a0 [ 44.177991 ] ? flush_work+0x20/0x20 [ 44.178257 ] ? lock_release+0x13c/0x8f0 [ 44.178550 ] ? __kasan_check_write+0x14/0x20 [ 44.178872 ] ? do_raw_spin_lock+0x148/0x360 [ 44.179187 ] ? read_lock_is_recursive+0x20/0x20 [ 44.179530 ] ? __kasan_check_read+0x11/0x20 [ 44.179846 ] ? do_raw_spin_unlock+0x55/0x900 [ 44.180168 ] ? ____kasan_slab_free+0x116/0x140 [ 44.180505 ] ? _raw_spin_unlock_irqrestore+0x41/0x60 [ 44.180878 ] ? skb_queue_purge+0x1a3/0x1c0 [ 44.181189 ] ? kfree+0x13e/0x290 [ 44.181438 ] flush_work+0x17/0x20 [ 44.181695 ] mISDN_freedchannel+0xe8/0x100 [ 44.182006 ] isac_release+0x210/0x260 [mISDNipac] [ 44.182366 ] nj_release+0xf6/0x500 [netjet] [ 44.182685 ] nj_remove+0x48/0x70 [netjet] [ 44.182989 ] pci_device_remove+0xa9/0x250
Signed-off-by: Zheyu Ma zheyuma97@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/isdn/hardware/mISDN/netjet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 2a1ddd47a096..a52f275f8263 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -949,8 +949,8 @@ nj_release(struct tiger_hw *card) nj_disable_hwirq(card); mode_tiger(&card->bc[0], ISDN_P_NONE); mode_tiger(&card->bc[1], ISDN_P_NONE); - card->isac.release(&card->isac); spin_unlock_irqrestore(&card->lock, flags); + card->isac.release(&card->isac); release_region(card->base, card->base_s); card->base_s = 0; }
From: Prashant Malani pmalani@chromium.org
[ Upstream commit 5c02b581ce84eea240d25c8318a1f65133a04415 ]
Commit a7d53dbbc70a ("platform/x86: intel_scu_ipc: Increase virtual timeout from 3 to 5 seconds") states that the recommended timeout range is 5-10 seconds. Adjust the timeout value to the higher of those i.e 10 seconds, to account for situations where the 5 seconds is insufficient for disconnect command success.
Signed-off-by: Prashant Malani pmalani@chromium.org Cc: Benson Leung bleung@chromium.org Reviewed-by: Mika Westerberg mika.westerberg@linux.intel.com Link: https://lore.kernel.org/r/20210928101932.2543937-3-pmalani@chromium.org Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 9171a46a9e3f..c78cd12ffca7 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -75,7 +75,7 @@ struct intel_scu_ipc_dev { #define IPC_READ_BUFFER 0x90
/* Timeout in jiffies */ -#define IPC_TIMEOUT (5 * HZ) +#define IPC_TIMEOUT (10 * HZ)
static struct intel_scu_ipc_dev *ipcdev; /* Only one for now */ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
From: Prashant Malani pmalani@chromium.org
[ Upstream commit a0c5814b9933f25ecb6de169483c5b88cf632bca ]
The comment decribing the IPC timeout hadn't been updated when the actual timeout was changed from 3 to 5 seconds in commit a7d53dbbc70a ("platform/x86: intel_scu_ipc: Increase virtual timeout from 3 to 5 seconds") .
Since the value is anyway updated to 10s now, take this opportunity to update the value in the comment too.
Signed-off-by: Prashant Malani pmalani@chromium.org Cc: Benson Leung bleung@chromium.org Reviewed-by: Mika Westerberg mika.westerberg@linux.intel.com Link: https://lore.kernel.org/r/20210928101932.2543937-4-pmalani@chromium.org Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index c78cd12ffca7..cb88017d595f 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -247,7 +247,7 @@ static inline int busy_loop(struct intel_scu_ipc_dev *scu) return -ETIMEDOUT; }
-/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ +/* Wait till ipc ioc interrupt is received or timeout in 10 HZ */ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu) { int status;
From: Kai Vehmanen kai.vehmanen@linux.intel.com
[ Upstream commit b37a15188eae9d4c49c5bb035e0c8d4058e4d9b3 ]
The snd_hdac_bus_reset_link() contains logic to clear STATESTS register before performing controller reset. This code dates back to an old bugfix in commit e8a7f136f5ed ("[ALSA] hda-intel - Improve HD-audio codec probing robustness"). Originally the code was added to azx_reset().
The code was moved around in commit a41d122449be ("ALSA: hda - Embed bus into controller object") and ended up to snd_hdac_bus_reset_link() and called primarily via snd_hdac_bus_init_chip().
The logic to clear STATESTS is correct when snd_hdac_bus_init_chip() is called when controller is not in reset. In this case, STATESTS can be cleared. This can be useful e.g. when forcing a controller reset to retry codec probe. A normal non-power-on reset will not clear the bits.
However, this old logic is problematic when controller is already in reset. The HDA specification states that controller must be taken out of reset before writing to registers other than GCTL.CRST (1.0a spec, 3.3.7). The write to STATESTS in snd_hdac_bus_reset_link() will be lost if the controller is already in reset per the HDA specification mentioned.
This has been harmless on older hardware. On newer generation of Intel PCIe based HDA controllers, if configured to report issues, this write will emit an unsupported request error. If ACPI Platform Error Interface (APEI) is enabled in kernel, this will end up to kernel log.
Fix the code in snd_hdac_bus_reset_link() to only clear the STATESTS if the function is called when controller is not in reset. Otherwise clearing the bits is not possible and should be skipped.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com Link: https://lore.kernel.org/r/20211012142935.3731820-1-kai.vehmanen@linux.intel.... Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Sasha Levin sashal@kernel.org --- sound/hda/hdac_controller.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 062da7a7a586..f7bd6e2db085 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -421,8 +421,9 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset) if (!full_reset) goto skip_reset;
- /* clear STATESTS */ - snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK); + /* clear STATESTS if not in reset */ + if (snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET) + snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
/* reset controller */ snd_hdac_bus_enter_link_reset(bus);
From: Mark Brown broonie@kernel.org
[ Upstream commit 6098475d4cb48d821bdf453c61118c56e26294f0 ]
Currently we have a global spi_add_lock which we take when adding new devices so that we can check that we're not trying to reuse a chip select that's already controlled. This means that if the SPI device is itself a SPI controller and triggers the instantiation of further SPI devices we trigger a deadlock as we try to register and instantiate those devices while in the process of doing so for the parent controller and hence already holding the global spi_add_lock. Since we only care about concurrency within a single SPI bus move the lock to be per controller, avoiding the deadlock.
This can be easily triggered in the case of spi-mux.
Reported-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/spi/spi.c | 17 ++++++----------- include/linux/spi/spi.h | 3 +++ 2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f95f7666cb5b..2c342bded058 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -480,12 +480,6 @@ static LIST_HEAD(spi_controller_list); */ static DEFINE_MUTEX(board_lock);
-/* - * Prevents addition of devices with same chip select and - * addition of devices below an unregistering controller. - */ -static DEFINE_MUTEX(spi_add_lock); - /** * spi_alloc_device - Allocate a new SPI device * @ctlr: Controller to which device is connected @@ -638,9 +632,9 @@ int spi_add_device(struct spi_device *spi) * chipselect **BEFORE** we call setup(), else we'll trash * its configuration. Lock against concurrent add() calls. */ - mutex_lock(&spi_add_lock); + mutex_lock(&ctlr->add_lock); status = __spi_add_device(spi); - mutex_unlock(&spi_add_lock); + mutex_unlock(&ctlr->add_lock); return status; } EXPORT_SYMBOL_GPL(spi_add_device); @@ -660,7 +654,7 @@ static int spi_add_device_locked(struct spi_device *spi) /* Set the bus ID string */ spi_dev_set_name(spi);
- WARN_ON(!mutex_is_locked(&spi_add_lock)); + WARN_ON(!mutex_is_locked(&ctlr->add_lock)); return __spi_add_device(spi); }
@@ -2832,6 +2826,7 @@ int spi_register_controller(struct spi_controller *ctlr) spin_lock_init(&ctlr->bus_lock_spinlock); mutex_init(&ctlr->bus_lock_mutex); mutex_init(&ctlr->io_mutex); + mutex_init(&ctlr->add_lock); ctlr->bus_lock_flag = 0; init_completion(&ctlr->xfer_completion); if (!ctlr->max_dma_len) @@ -2968,7 +2963,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
/* Prevent addition of new devices, unregister existing ones */ if (IS_ENABLED(CONFIG_SPI_DYNAMIC)) - mutex_lock(&spi_add_lock); + mutex_lock(&ctlr->add_lock);
device_for_each_child(&ctlr->dev, NULL, __unregister);
@@ -2999,7 +2994,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) mutex_unlock(&board_lock);
if (IS_ENABLED(CONFIG_SPI_DYNAMIC)) - mutex_unlock(&spi_add_lock); + mutex_unlock(&ctlr->add_lock); } EXPORT_SYMBOL_GPL(spi_unregister_controller);
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 97b8d12b5f2b..5d80c6fd2a22 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -527,6 +527,9 @@ struct spi_controller { /* I/O mutex */ struct mutex io_mutex;
+ /* Used to avoid adding the same CS twice */ + struct mutex add_lock; + /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex;
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit 16a8e2fbb2d49111004efc1c7342e083eafabeb0 ]
io_mutex is taken by spi_setup() and spi-mux's .setup() callback calls spi_setup() which results in a nested lock of io_mutex.
add_lock is taken by spi_add_device(). The device_add() call in there can result in calling spi-mux's .probe() callback which registers its own spi controller which in turn results in spi_add_device() being called again.
To fix this initialize the controller's locks already in spi_alloc_controller() to give spi_mux_probe() a chance to set the lockdep subclass.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Link: https://lore.kernel.org/r/20211013133710.2679703-2-u.kleine-koenig@pengutron... Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/spi/spi-mux.c | 7 +++++++ drivers/spi/spi.c | 12 ++++++------ 2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c index 9708b7827ff7..f5d32ec4634e 100644 --- a/drivers/spi/spi-mux.c +++ b/drivers/spi/spi-mux.c @@ -137,6 +137,13 @@ static int spi_mux_probe(struct spi_device *spi) priv = spi_controller_get_devdata(ctlr); priv->spi = spi;
+ /* + * Increase lockdep class as these lock are taken while the parent bus + * already holds their instance's lock. + */ + lockdep_set_subclass(&ctlr->io_mutex, 1); + lockdep_set_subclass(&ctlr->add_lock, 1); + priv->mux = devm_mux_control_get(&spi->dev, NULL); if (IS_ERR(priv->mux)) { ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux), diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2c342bded058..3093e0041158 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2549,6 +2549,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev, return NULL;
device_initialize(&ctlr->dev); + INIT_LIST_HEAD(&ctlr->queue); + spin_lock_init(&ctlr->queue_lock); + spin_lock_init(&ctlr->bus_lock_spinlock); + mutex_init(&ctlr->bus_lock_mutex); + mutex_init(&ctlr->io_mutex); + mutex_init(&ctlr->add_lock); ctlr->bus_num = -1; ctlr->num_chipselect = 1; ctlr->slave = slave; @@ -2821,12 +2827,6 @@ int spi_register_controller(struct spi_controller *ctlr) return id; ctlr->bus_num = id; } - INIT_LIST_HEAD(&ctlr->queue); - spin_lock_init(&ctlr->queue_lock); - spin_lock_init(&ctlr->bus_lock_spinlock); - mutex_init(&ctlr->bus_lock_mutex); - mutex_init(&ctlr->io_mutex); - mutex_init(&ctlr->add_lock); ctlr->bus_lock_flag = 0; init_completion(&ctlr->xfer_completion); if (!ctlr->max_dma_len)
From: Shunsuke Nakamura nakamura.shun@fujitsu.com
[ Upstream commit f304c8d949f9adc2ef51304b63e49d5ea1c2d288 ]
In test_stat_user_read, following build error occurs except i386 and x86_64 architectures:
tests/test-evsel.c:129:31: error: variable 'pc' set but not used [-Werror=unused-but-set-variable] struct perf_event_mmap_page *pc;
Fix build error.
Signed-off-by: Shunsuke Nakamura nakamura.shun@fujitsu.com Acked-by: Jiri Olsa jolsa@redhat.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Ingo Molnar mingo@redhat.com Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20211006095703.477826-1-nakamura.shun@fujitsu.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- tools/lib/perf/tests/test-evsel.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/lib/perf/tests/test-evsel.c b/tools/lib/perf/tests/test-evsel.c index a184e4861627..9abd4c0bf6db 100644 --- a/tools/lib/perf/tests/test-evsel.c +++ b/tools/lib/perf/tests/test-evsel.c @@ -148,6 +148,7 @@ static int test_stat_user_read(int event) __T("failed to mmap evsel", err == 0);
pc = perf_evsel__mmap_base(evsel, 0, 0); + __T("failed to get mmapped address", pc);
#if defined(__i386__) || defined(__x86_64__) __T("userspace counter access not supported", pc->cap_user_rdpmc);
From: Shunsuke Nakamura nakamura.shun@fujitsu.com
[ Upstream commit 3ff6d64e68abc231955d216236615918797614ae ]
The `cpu` argument of perf_evsel__read() must specify the cpu index.
perf_cpu_map__for_each_cpu() is for iterating the cpu number (not index) and is thus not appropriate for use with perf_evsel__read().
So, if there is an offline CPU, the cpu number specified in the argument may point out of range because the cpu number and the cpu index are different.
Fix test_stat_cpu().
Testing it:
# make tests -C tools/lib/perf/ make: Entering directory '/home/nakamura/kernel_src/linux-5.15-rc4_fix/tools/lib/perf' running static: - running tests/test-cpumap.c...OK - running tests/test-threadmap.c...OK - running tests/test-evlist.c...OK - running tests/test-evsel.c...OK running dynamic: - running tests/test-cpumap.c...OK - running tests/test-threadmap.c...OK - running tests/test-evlist.c...OK - running tests/test-evsel.c...OK make: Leaving directory '/home/nakamura/kernel_src/linux-5.15-rc4_fix/tools/lib/perf'
Signed-off-by: Shunsuke Nakamura nakamura.shun@fujitsu.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Link: http://lore.kernel.org/lkml/20211011083704.4108720-1-nakamura.shun@fujitsu.c... Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- tools/lib/perf/tests/test-evlist.c | 6 +++--- tools/lib/perf/tests/test-evsel.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c index c67c83399170..ce91a582f0e4 100644 --- a/tools/lib/perf/tests/test-evlist.c +++ b/tools/lib/perf/tests/test-evlist.c @@ -40,7 +40,7 @@ static int test_stat_cpu(void) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK, }; - int err, cpu, tmp; + int err, idx;
cpus = perf_cpu_map__new(NULL); __T("failed to create cpus", cpus); @@ -70,10 +70,10 @@ static int test_stat_cpu(void) perf_evlist__for_each_evsel(evlist, evsel) { cpus = perf_evsel__cpus(evsel);
- perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { + for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { struct perf_counts_values counts = { .val = 0 };
- perf_evsel__read(evsel, cpu, 0, &counts); + perf_evsel__read(evsel, idx, 0, &counts); __T("failed to read value for evsel", counts.val != 0); } } diff --git a/tools/lib/perf/tests/test-evsel.c b/tools/lib/perf/tests/test-evsel.c index 9abd4c0bf6db..33ae9334861a 100644 --- a/tools/lib/perf/tests/test-evsel.c +++ b/tools/lib/perf/tests/test-evsel.c @@ -22,7 +22,7 @@ static int test_stat_cpu(void) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, }; - int err, cpu, tmp; + int err, idx;
cpus = perf_cpu_map__new(NULL); __T("failed to create cpus", cpus); @@ -33,10 +33,10 @@ static int test_stat_cpu(void) err = perf_evsel__open(evsel, cpus, NULL); __T("failed to open evsel", err == 0);
- perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { + for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { struct perf_counts_values counts = { .val = 0 };
- perf_evsel__read(evsel, cpu, 0, &counts); + perf_evsel__read(evsel, idx, 0, &counts); __T("failed to read value for evsel", counts.val != 0); }
From: Kan Liang kan.liang@linux.intel.com
[ Upstream commit 71920ea97d6d1d800ee8b51951dc3fda3f5dc698 ]
SMI_COUNT MSR is supported on Sapphire Rapids CPU.
Signed-off-by: Kan Liang kan.liang@linux.intel.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Link: https://lkml.kernel.org/r/1633551137-192083-1-git-send-email-kan.liang@linux... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/x86/events/msr.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index c853b28efa33..96c775abe31f 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -68,6 +68,7 @@ static bool test_intel(int idx, void *data) case INTEL_FAM6_BROADWELL_D: case INTEL_FAM6_BROADWELL_G: case INTEL_FAM6_BROADWELL_X: + case INTEL_FAM6_SAPPHIRERAPIDS_X:
case INTEL_FAM6_ATOM_SILVERMONT: case INTEL_FAM6_ATOM_SILVERMONT_D:
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit d997cc1715df7b6c3df798881fb9941acf0079f8 ]
On i.MX7S and i.MX8M* (but not i.MX6*) the pwrkey device has an associated clock. Accessing the registers requires that this clock is enabled. Binding the driver on at least i.MX7S and i.MX8MP while not having the clock enabled results in a complete hang of the machine. (This usually only happens if snvs_pwrkey is built as a module and the rtc-snvs driver isn't already bound because at bootup the required clk is on and only gets disabled when the clk framework disables unused clks late during boot.)
This completes the fix in commit 135be16d3505 ("ARM: dts: imx7s: add snvs clock to pwrkey").
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Link: https://lore.kernel.org/r/20211013062848.2667192-1-u.kleine-koenig@pengutron... Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/input/keyboard/snvs_pwrkey.c | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 2f5e3ab5ed63..65286762b02a 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -3,6 +3,7 @@ // Driver for the IMX SNVS ON/OFF Power Key // Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+#include <linux/clk.h> #include <linux/device.h> #include <linux/err.h> #include <linux/init.h> @@ -99,6 +100,11 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) return IRQ_HANDLED; }
+static void imx_snvs_pwrkey_disable_clk(void *data) +{ + clk_disable_unprepare(data); +} + static void imx_snvs_pwrkey_act(void *pdata) { struct pwrkey_drv_data *pd = pdata; @@ -111,6 +117,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) struct pwrkey_drv_data *pdata; struct input_dev *input; struct device_node *np; + struct clk *clk; int error; u32 vid;
@@ -134,6 +141,28 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); }
+ clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk); + return PTR_ERR(clk); + } + + error = clk_prepare_enable(clk); + if (error) { + dev_err(&pdev->dev, "Failed to enable snvs clock (%pe)\n", + ERR_PTR(error)); + return error; + } + + error = devm_add_action_or_reset(&pdev->dev, + imx_snvs_pwrkey_disable_clk, clk); + if (error) { + dev_err(&pdev->dev, + "Failed to register clock cleanup handler (%pe)\n", + ERR_PTR(error)); + return error; + } + pdata->wakeup = of_property_read_bool(np, "wakeup-source");
pdata->irq = platform_get_irq(pdev, 0);
From: Michael Cullen michael@michaelcullen.name
[ Upstream commit 3378a07daa6cdd11e042797454c706d1c69f9ca6 ]
The Nacon GX100XF is already mapped, but it seems there is a Nacon GC-100 (identified as NC5136Wht PCGC-100WHITE though I believe other colours exist) with a different USB ID when in XInput mode.
Signed-off-by: Michael Cullen michael@michaelcullen.name Link: https://lore.kernel.org/r/20211015192051.5196-1-michael@michaelcullen.name Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/input/joystick/xpad.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 29de8412e416..4c914f75a902 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -334,6 +334,7 @@ static const struct xpad_device { { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, + { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } @@ -451,6 +452,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */ XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */ + XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ { } };
linux-stable-mirror@lists.linaro.org