From e5eaa1bbe2813ac34788e485283be75f9d07137b Mon Sep 17 00:00:00 2001 From: Carlos Bilbao Date: Wed, 29 Jan 2025 19:22:44 -0600 Subject: [PATCH 01/16] mailmap, MAINTAINERS, docs: update Carlos's email address Update .mailmap to reflect my new (and final) primary email address, carlos.bilbao@kernel.org. Also update contact information in files Documentation/translations/sp_SP/index.rst and MAINTAINERS. Link: https://lkml.kernel.org/r/20250130012248.1196208-1-carlos.bilbao@kernel.org Signed-off-by: Carlos Bilbao Cc: Carlos Bilbao Cc: Jonathan Corbet Cc: Mattew Wilcox Signed-off-by: Andrew Morton --- .mailmap | 4 +++- Documentation/translations/sp_SP/index.rst | 2 +- MAINTAINERS | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index fec6b455b576..9a270c53675b 100644 --- a/.mailmap +++ b/.mailmap @@ -148,7 +148,9 @@ Bryan Tan Cai Huoqing Can Guo Carl Huang -Carlos Bilbao +Carlos Bilbao +Carlos Bilbao +Carlos Bilbao Changbin Du Changbin Du Chao Yu diff --git a/Documentation/translations/sp_SP/index.rst b/Documentation/translations/sp_SP/index.rst index aae7018b0d1a..2b50283e1608 100644 --- a/Documentation/translations/sp_SP/index.rst +++ b/Documentation/translations/sp_SP/index.rst @@ -7,7 +7,7 @@ Traducción al español \kerneldocCJKoff -:maintainer: Carlos Bilbao +:maintainer: Carlos Bilbao .. _sp_disclaimer: diff --git a/MAINTAINERS b/MAINTAINERS index d269d3c6e317..1824df1f61f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1090,7 +1090,7 @@ F: drivers/video/fbdev/geode/ AMD HSMP DRIVER M: Naveen Krishna Chatradhi -R: Carlos Bilbao +R: Carlos Bilbao L: platform-driver-x86@vger.kernel.org S: Maintained F: Documentation/arch/x86/amd_hsmp.rst @@ -5856,7 +5856,7 @@ F: drivers/usb/atm/cxacru.c CONFIDENTIAL COMPUTING THREAT MODEL FOR X86 VIRTUALIZATION (SNP/TDX) M: Elena Reshetova -M: Carlos Bilbao +M: Carlos Bilbao S: Maintained F: Documentation/security/snp-tdx-threat-model.rst @@ -11323,7 +11323,7 @@ S: Orphan F: drivers/video/fbdev/imsttfb.c INDEX OF FURTHER KERNEL DOCUMENTATION -M: Carlos Bilbao +M: Carlos Bilbao S: Maintained F: Documentation/process/kernel-docs.rst @@ -22205,7 +22205,7 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/dvb-frontends/sp2* SPANISH DOCUMENTATION -M: Carlos Bilbao +M: Carlos Bilbao R: Avadhut Naik S: Maintained F: Documentation/translations/sp_SP/ -- 2.51.0 From 0ca2a41e0ccc573845428b686ff09e9322c82b16 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 29 Jan 2025 16:13:49 -0500 Subject: [PATCH 02/16] MAINTAINERS: add lib/test_xarray.c Ensure test-only changes are sent to the relevant maintainer. Link: https://lkml.kernel.org/r/20250129-xarray-test-maintainer-v1-1-482e31f30f47@gmail.com Signed-off-by: Tamir Duberstein Cc: Mattew Wilcox Signed-off-by: Andrew Morton --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1824df1f61f0..f52a004982c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25734,6 +25734,7 @@ F: Documentation/core-api/xarray.rst F: include/linux/idr.h F: include/linux/xarray.h F: lib/idr.c +F: lib/test_xarray.c F: lib/xarray.c F: tools/testing/radix-tree -- 2.51.0 From 050339050f6f2b18d32a61a0f725f423804ad2a5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 30 Jan 2025 16:09:20 -0800 Subject: [PATCH 03/16] revert "xarray: port tests to kunit" Revert c7bb5cf9fc4e ("xarray: port tests to kunit"). It broke the build when compiing the xarray userspace test harness code. Reported-by: Sidhartha Kumar Closes: https://lkml.kernel.org/r/07cf896e-adf8-414f-a629-a808fc26014a@oracle.com Cc: David Gow Cc: Matthew Wilcox Cc: Tamir Duberstein Cc: "Liam R. Howlett" Cc: Geert Uytterhoeven Cc: Lorenzo Stoakes Signed-off-by: Andrew Morton --- arch/m68k/configs/amiga_defconfig | 1 + arch/m68k/configs/apollo_defconfig | 1 + arch/m68k/configs/atari_defconfig | 1 + arch/m68k/configs/bvme6000_defconfig | 1 + arch/m68k/configs/hp300_defconfig | 1 + arch/m68k/configs/mac_defconfig | 1 + arch/m68k/configs/multi_defconfig | 1 + arch/m68k/configs/mvme147_defconfig | 1 + arch/m68k/configs/mvme16x_defconfig | 1 + arch/m68k/configs/q40_defconfig | 1 + arch/m68k/configs/sun3_defconfig | 1 + arch/m68k/configs/sun3x_defconfig | 1 + arch/powerpc/configs/ppc64_defconfig | 1 + lib/Kconfig.debug | 18 +- lib/Makefile | 2 +- lib/test_xarray.c | 671 +++++++++++---------------- 16 files changed, 294 insertions(+), 410 deletions(-) diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 8acfa66e1095..dbf2ea561c85 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -626,6 +626,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 35e9a0872304..b0fd199cc0a4 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -583,6 +583,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 32891ddd3cc5..bb5b2d3b6c10 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -603,6 +603,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index ca276f0db3dd..8315a13bab73 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -575,6 +575,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index e83f14fe1a4f..350370657e5f 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -585,6 +585,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 6b58be24da79..f942b4755702 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -602,6 +602,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 0e8d24f82565..b1eaad02efab 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -689,6 +689,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 24a7608c13ac..6309a4442bb3 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -575,6 +575,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index c415f75821f3..3feb0731f814 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -576,6 +576,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 2c715a8ff551..ea04b1b0da7d 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -592,6 +592,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 15ff37fcccbf..f52d9af92153 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -572,6 +572,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 40a44bf9f48d..f348447824da 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -573,6 +573,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index e9c46b59ebbc..465eb96c755e 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -448,6 +448,7 @@ CONFIG_TEST_PRINTF=m CONFIG_TEST_SCANF=m CONFIG_TEST_BITMAP=m CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m CONFIG_TEST_MAPLE_TREE=m CONFIG_TEST_RHASHTABLE=m CONFIG_TEST_IDA=m diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 775966cf6114..1af972a92d06 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2456,22 +2456,8 @@ config TEST_BITMAP config TEST_UUID tristate "Test functions located in the uuid module at runtime" -config XARRAY_KUNIT - tristate "KUnit test XArray code at runtime" if !KUNIT_ALL_TESTS - depends on KUNIT - default KUNIT_ALL_TESTS - help - Enable this option to test the Xarray code at boot. - - KUnit tests run during boot and output the results to the debug log - in TAP format (http://testanything.org/). Only useful for kernel devs - running the KUnit test harness, and not intended for inclusion into a - production build. - - For more information on KUnit and unit tests in general please refer - to the KUnit documentation in Documentation/dev-tools/kunit/. - - If unsure, say N. +config TEST_XARRAY + tristate "Test the XArray code at runtime" config TEST_MAPLE_TREE tristate "Test the Maple Tree code at runtime or module load" diff --git a/lib/Makefile b/lib/Makefile index f1c6e9d76a7c..d5cfc7afbbb8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -94,6 +94,7 @@ GCOV_PROFILE_test_bitmap.o := n endif obj-$(CONFIG_TEST_UUID) += test_uuid.o +obj-$(CONFIG_TEST_XARRAY) += test_xarray.o obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o obj-$(CONFIG_TEST_PARMAN) += test_parman.o obj-$(CONFIG_TEST_KMOD) += test_kmod.o @@ -372,7 +373,6 @@ CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN) obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o -obj-$(CONFIG_XARRAY_KUNIT) += test_xarray.o obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o diff --git a/lib/test_xarray.c b/lib/test_xarray.c index eab5971d0a48..6932a26f4927 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -6,10 +6,11 @@ * Author: Matthew Wilcox */ -#include - -#include #include +#include + +static unsigned int tests_run; +static unsigned int tests_passed; static const unsigned int order_limit = IS_ENABLED(CONFIG_XARRAY_MULTI) ? BITS_PER_LONG : 1; @@ -19,12 +20,15 @@ static const unsigned int order_limit = void xa_dump(const struct xarray *xa) { } # endif #undef XA_BUG_ON -#define XA_BUG_ON(xa, x) do { \ - if (x) { \ - KUNIT_FAIL(test, #x); \ - xa_dump(xa); \ - dump_stack(); \ - } \ +#define XA_BUG_ON(xa, x) do { \ + tests_run++; \ + if (x) { \ + printk("BUG at %s:%d\n", __func__, __LINE__); \ + xa_dump(xa); \ + dump_stack(); \ + } else { \ + tests_passed++; \ + } \ } while (0) #endif @@ -38,13 +42,13 @@ static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp) return xa_store(xa, index, xa_mk_index(index), gfp); } -static void xa_insert_index(struct kunit *test, struct xarray *xa, unsigned long index) +static void xa_insert_index(struct xarray *xa, unsigned long index) { XA_BUG_ON(xa, xa_insert(xa, index, xa_mk_index(index), GFP_KERNEL) != 0); } -static void xa_alloc_index(struct kunit *test, struct xarray *xa, unsigned long index, gfp_t gfp) +static void xa_alloc_index(struct xarray *xa, unsigned long index, gfp_t gfp) { u32 id; @@ -53,7 +57,7 @@ static void xa_alloc_index(struct kunit *test, struct xarray *xa, unsigned long XA_BUG_ON(xa, id != index); } -static void xa_erase_index(struct kunit *test, struct xarray *xa, unsigned long index) +static void xa_erase_index(struct xarray *xa, unsigned long index) { XA_BUG_ON(xa, xa_erase(xa, index) != xa_mk_index(index)); XA_BUG_ON(xa, xa_load(xa, index) != NULL); @@ -79,15 +83,8 @@ static void *xa_store_order(struct xarray *xa, unsigned long index, return curr; } -static inline struct xarray *xa_param(struct kunit *test) +static noinline void check_xa_err(struct xarray *xa) { - return *(struct xarray **)test->param_value; -} - -static noinline void check_xa_err(struct kunit *test) -{ - struct xarray *xa = xa_param(test); - XA_BUG_ON(xa, xa_err(xa_store_index(xa, 0, GFP_NOWAIT)) != 0); XA_BUG_ON(xa, xa_err(xa_erase(xa, 0)) != 0); #ifndef __KERNEL__ @@ -102,10 +99,8 @@ static noinline void check_xa_err(struct kunit *test) // XA_BUG_ON(xa, xa_err(xa_store(xa, 0, xa_mk_internal(0), 0)) != -EINVAL); } -static noinline void check_xas_retry(struct kunit *test) +static noinline void check_xas_retry(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); void *entry; @@ -114,7 +109,7 @@ static noinline void check_xas_retry(struct kunit *test) rcu_read_lock(); XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_value(0)); - xa_erase_index(test, xa, 1); + xa_erase_index(xa, 1); XA_BUG_ON(xa, !xa_is_retry(xas_reload(&xas))); XA_BUG_ON(xa, xas_retry(&xas, NULL)); XA_BUG_ON(xa, xas_retry(&xas, xa_mk_value(0))); @@ -145,14 +140,12 @@ static noinline void check_xas_retry(struct kunit *test) } xas_unlock(&xas); - xa_erase_index(test, xa, 0); - xa_erase_index(test, xa, 1); + xa_erase_index(xa, 0); + xa_erase_index(xa, 1); } -static noinline void check_xa_load(struct kunit *test) +static noinline void check_xa_load(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned long i, j; for (i = 0; i < 1024; i++) { @@ -174,15 +167,13 @@ static noinline void check_xa_load(struct kunit *test) else XA_BUG_ON(xa, entry); } - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); } XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_xa_mark_1(struct kunit *test, unsigned long index) +static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index) { - struct xarray *xa = xa_param(test); - unsigned int order; unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 8 : 1; @@ -202,7 +193,7 @@ static noinline void check_xa_mark_1(struct kunit *test, unsigned long index) XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1)); /* Storing NULL clears marks, and they can't be set again */ - xa_erase_index(test, xa, index); + xa_erase_index(xa, index); XA_BUG_ON(xa, !xa_empty(xa)); XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); xa_set_mark(xa, index, XA_MARK_0); @@ -253,17 +244,15 @@ static noinline void check_xa_mark_1(struct kunit *test, unsigned long index) XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_0)); XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_1)); XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_2)); - xa_erase_index(test, xa, index); - xa_erase_index(test, xa, next); + xa_erase_index(xa, index); + xa_erase_index(xa, next); XA_BUG_ON(xa, !xa_empty(xa)); } XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_xa_mark_2(struct kunit *test) +static noinline void check_xa_mark_2(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); unsigned long index; unsigned int count = 0; @@ -300,11 +289,9 @@ static noinline void check_xa_mark_2(struct kunit *test) xa_destroy(xa); } -static noinline void check_xa_mark_3(struct kunit *test) +static noinline void check_xa_mark_3(struct xarray *xa) { #ifdef CONFIG_XARRAY_MULTI - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0x41); void *entry; int count = 0; @@ -323,21 +310,19 @@ static noinline void check_xa_mark_3(struct kunit *test) #endif } -static noinline void check_xa_mark(struct kunit *test) +static noinline void check_xa_mark(struct xarray *xa) { unsigned long index; for (index = 0; index < 16384; index += 4) - check_xa_mark_1(test, index); + check_xa_mark_1(xa, index); - check_xa_mark_2(test); - check_xa_mark_3(test); + check_xa_mark_2(xa); + check_xa_mark_3(xa); } -static noinline void check_xa_shrink(struct kunit *test) +static noinline void check_xa_shrink(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 1); struct xa_node *node; unsigned int order; @@ -362,7 +347,7 @@ static noinline void check_xa_shrink(struct kunit *test) XA_BUG_ON(xa, xas_load(&xas) != NULL); xas_unlock(&xas); XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0)); - xa_erase_index(test, xa, 0); + xa_erase_index(xa, 0); XA_BUG_ON(xa, !xa_empty(xa)); for (order = 0; order < max_order; order++) { @@ -379,49 +364,45 @@ static noinline void check_xa_shrink(struct kunit *test) XA_BUG_ON(xa, xa_head(xa) == node); rcu_read_unlock(); XA_BUG_ON(xa, xa_load(xa, max + 1) != NULL); - xa_erase_index(test, xa, ULONG_MAX); + xa_erase_index(xa, ULONG_MAX); XA_BUG_ON(xa, xa->xa_head != node); - xa_erase_index(test, xa, 0); + xa_erase_index(xa, 0); } } -static noinline void check_insert(struct kunit *test) +static noinline void check_insert(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned long i; for (i = 0; i < 1024; i++) { - xa_insert_index(test, xa, i); + xa_insert_index(xa, i); XA_BUG_ON(xa, xa_load(xa, i - 1) != NULL); XA_BUG_ON(xa, xa_load(xa, i + 1) != NULL); - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); } for (i = 10; i < BITS_PER_LONG; i++) { - xa_insert_index(test, xa, 1UL << i); + xa_insert_index(xa, 1UL << i); XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 1) != NULL); XA_BUG_ON(xa, xa_load(xa, (1UL << i) + 1) != NULL); - xa_erase_index(test, xa, 1UL << i); + xa_erase_index(xa, 1UL << i); - xa_insert_index(test, xa, (1UL << i) - 1); + xa_insert_index(xa, (1UL << i) - 1); XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 2) != NULL); XA_BUG_ON(xa, xa_load(xa, 1UL << i) != NULL); - xa_erase_index(test, xa, (1UL << i) - 1); + xa_erase_index(xa, (1UL << i) - 1); } - xa_insert_index(test, xa, ~0UL); + xa_insert_index(xa, ~0UL); XA_BUG_ON(xa, xa_load(xa, 0UL) != NULL); XA_BUG_ON(xa, xa_load(xa, ~1UL) != NULL); - xa_erase_index(test, xa, ~0UL); + xa_erase_index(xa, ~0UL); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_cmpxchg(struct kunit *test) +static noinline void check_cmpxchg(struct xarray *xa) { - struct xarray *xa = xa_param(test); - void *FIVE = xa_mk_value(5); void *SIX = xa_mk_value(6); void *LOTS = xa_mk_value(12345678); @@ -437,16 +418,14 @@ static noinline void check_cmpxchg(struct kunit *test) XA_BUG_ON(xa, xa_insert(xa, 5, FIVE, GFP_KERNEL) != -EBUSY); XA_BUG_ON(xa, xa_cmpxchg(xa, 5, FIVE, NULL, GFP_KERNEL) != FIVE); XA_BUG_ON(xa, xa_insert(xa, 5, FIVE, GFP_KERNEL) == -EBUSY); - xa_erase_index(test, xa, 12345678); - xa_erase_index(test, xa, 5); + xa_erase_index(xa, 12345678); + xa_erase_index(xa, 5); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_cmpxchg_order(struct kunit *test) +static noinline void check_cmpxchg_order(struct xarray *xa) { #ifdef CONFIG_XARRAY_MULTI - struct xarray *xa = xa_param(test); - void *FIVE = xa_mk_value(5); unsigned int i, order = 3; @@ -497,10 +476,8 @@ static noinline void check_cmpxchg_order(struct kunit *test) #endif } -static noinline void check_reserve(struct kunit *test) +static noinline void check_reserve(struct xarray *xa) { - struct xarray *xa = xa_param(test); - void *entry; unsigned long index; int count; @@ -517,7 +494,7 @@ static noinline void check_reserve(struct kunit *test) XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0); XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_NOWAIT) != NULL); xa_release(xa, 12345678); - xa_erase_index(test, xa, 12345678); + xa_erase_index(xa, 12345678); XA_BUG_ON(xa, !xa_empty(xa)); /* cmpxchg sees a reserved entry as ZERO */ @@ -525,7 +502,7 @@ static noinline void check_reserve(struct kunit *test) XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, XA_ZERO_ENTRY, xa_mk_value(12345678), GFP_NOWAIT) != NULL); xa_release(xa, 12345678); - xa_erase_index(test, xa, 12345678); + xa_erase_index(xa, 12345678); XA_BUG_ON(xa, !xa_empty(xa)); /* xa_insert treats it as busy */ @@ -565,10 +542,8 @@ static noinline void check_reserve(struct kunit *test) xa_destroy(xa); } -static noinline void check_xas_erase(struct kunit *test) +static noinline void check_xas_erase(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); void *entry; unsigned long i, j; @@ -606,11 +581,9 @@ static noinline void check_xas_erase(struct kunit *test) } #ifdef CONFIG_XARRAY_MULTI -static noinline void check_multi_store_1(struct kunit *test, unsigned long index, +static noinline void check_multi_store_1(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, index); unsigned long min = index & ~((1UL << order) - 1); unsigned long max = min + (1UL << order); @@ -629,15 +602,13 @@ static noinline void check_multi_store_1(struct kunit *test, unsigned long index XA_BUG_ON(xa, xa_load(xa, max) != NULL); XA_BUG_ON(xa, xa_load(xa, min - 1) != NULL); - xa_erase_index(test, xa, min); + xa_erase_index(xa, min); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_multi_store_2(struct kunit *test, unsigned long index, +static noinline void check_multi_store_2(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, index); xa_store_order(xa, index, order, xa_mk_value(0), GFP_KERNEL); @@ -649,11 +620,9 @@ static noinline void check_multi_store_2(struct kunit *test, unsigned long index XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_multi_store_3(struct kunit *test, unsigned long index, +static noinline void check_multi_store_3(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); void *entry; int n = 0; @@ -678,11 +647,9 @@ static noinline void check_multi_store_3(struct kunit *test, unsigned long index } #endif -static noinline void check_multi_store(struct kunit *test) +static noinline void check_multi_store(struct xarray *xa) { #ifdef CONFIG_XARRAY_MULTI - struct xarray *xa = xa_param(test); - unsigned long i, j, k; unsigned int max_order = (sizeof(long) == 4) ? 30 : 60; @@ -747,28 +714,26 @@ static noinline void check_multi_store(struct kunit *test) } for (i = 0; i < 20; i++) { - check_multi_store_1(test, 200, i); - check_multi_store_1(test, 0, i); - check_multi_store_1(test, (1UL << i) + 1, i); + check_multi_store_1(xa, 200, i); + check_multi_store_1(xa, 0, i); + check_multi_store_1(xa, (1UL << i) + 1, i); } - check_multi_store_2(test, 4095, 9); + check_multi_store_2(xa, 4095, 9); for (i = 1; i < 20; i++) { - check_multi_store_3(test, 0, i); - check_multi_store_3(test, 1UL << i, i); + check_multi_store_3(xa, 0, i); + check_multi_store_3(xa, 1UL << i, i); } #endif } #ifdef CONFIG_XARRAY_MULTI /* mimics page cache __filemap_add_folio() */ -static noinline void check_xa_multi_store_adv_add(struct kunit *test, +static noinline void check_xa_multi_store_adv_add(struct xarray *xa, unsigned long index, unsigned int order, void *p) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, index); unsigned int nrpages = 1UL << order; @@ -796,12 +761,10 @@ static noinline void check_xa_multi_store_adv_add(struct kunit *test, } /* mimics page_cache_delete() */ -static noinline void check_xa_multi_store_adv_del_entry(struct kunit *test, +static noinline void check_xa_multi_store_adv_del_entry(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, index); xas_set_order(&xas, index, order); @@ -809,14 +772,12 @@ static noinline void check_xa_multi_store_adv_del_entry(struct kunit *test, xas_init_marks(&xas); } -static noinline void check_xa_multi_store_adv_delete(struct kunit *test, +static noinline void check_xa_multi_store_adv_delete(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - xa_lock_irq(xa); - check_xa_multi_store_adv_del_entry(test, index, order); + check_xa_multi_store_adv_del_entry(xa, index, order); xa_unlock_irq(xa); } @@ -853,12 +814,10 @@ static unsigned long some_val = 0xdeadbeef; static unsigned long some_val_2 = 0xdeaddead; /* mimics the page cache usage */ -static noinline void check_xa_multi_store_adv(struct kunit *test, +static noinline void check_xa_multi_store_adv(struct xarray *xa, unsigned long pos, unsigned int order) { - struct xarray *xa = xa_param(test); - unsigned int nrpages = 1UL << order; unsigned long index, base, next_index, next_next_index; unsigned int i; @@ -868,7 +827,7 @@ static noinline void check_xa_multi_store_adv(struct kunit *test, next_index = round_down(base + nrpages, nrpages); next_next_index = round_down(next_index + nrpages, nrpages); - check_xa_multi_store_adv_add(test, base, order, &some_val); + check_xa_multi_store_adv_add(xa, base, order, &some_val); for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, base + i) != &some_val); @@ -876,20 +835,20 @@ static noinline void check_xa_multi_store_adv(struct kunit *test, XA_BUG_ON(xa, test_get_entry(xa, next_index) != NULL); /* Use order 0 for the next item */ - check_xa_multi_store_adv_add(test, next_index, 0, &some_val_2); + check_xa_multi_store_adv_add(xa, next_index, 0, &some_val_2); XA_BUG_ON(xa, test_get_entry(xa, next_index) != &some_val_2); /* Remove the next item */ - check_xa_multi_store_adv_delete(test, next_index, 0); + check_xa_multi_store_adv_delete(xa, next_index, 0); /* Now use order for a new pointer */ - check_xa_multi_store_adv_add(test, next_index, order, &some_val_2); + check_xa_multi_store_adv_add(xa, next_index, order, &some_val_2); for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, next_index + i) != &some_val_2); - check_xa_multi_store_adv_delete(test, next_index, order); - check_xa_multi_store_adv_delete(test, base, order); + check_xa_multi_store_adv_delete(xa, next_index, order); + check_xa_multi_store_adv_delete(xa, base, order); XA_BUG_ON(xa, !xa_empty(xa)); /* starting fresh again */ @@ -897,7 +856,7 @@ static noinline void check_xa_multi_store_adv(struct kunit *test, /* let's test some holes now */ /* hole at base and next_next */ - check_xa_multi_store_adv_add(test, next_index, order, &some_val_2); + check_xa_multi_store_adv_add(xa, next_index, order, &some_val_2); for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, base + i) != NULL); @@ -908,12 +867,12 @@ static noinline void check_xa_multi_store_adv(struct kunit *test, for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, next_next_index + i) != NULL); - check_xa_multi_store_adv_delete(test, next_index, order); + check_xa_multi_store_adv_delete(xa, next_index, order); XA_BUG_ON(xa, !xa_empty(xa)); /* hole at base and next */ - check_xa_multi_store_adv_add(test, next_next_index, order, &some_val_2); + check_xa_multi_store_adv_add(xa, next_next_index, order, &some_val_2); for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, base + i) != NULL); @@ -924,12 +883,12 @@ static noinline void check_xa_multi_store_adv(struct kunit *test, for (i = 0; i < nrpages; i++) XA_BUG_ON(xa, test_get_entry(xa, next_next_index + i) != &some_val_2); - check_xa_multi_store_adv_delete(test, next_next_index, order); + check_xa_multi_store_adv_delete(xa, next_next_index, order); XA_BUG_ON(xa, !xa_empty(xa)); } #endif -static noinline void check_multi_store_advanced(struct kunit *test) +static noinline void check_multi_store_advanced(struct xarray *xa) { #ifdef CONFIG_XARRAY_MULTI unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1; @@ -941,59 +900,59 @@ static noinline void check_multi_store_advanced(struct kunit *test) */ for (pos = 7; pos < end; pos = (pos * pos) + 564) { for (i = 0; i < max_order; i++) { - check_xa_multi_store_adv(test, pos, i); - check_xa_multi_store_adv(test, pos + 157, i); + check_xa_multi_store_adv(xa, pos, i); + check_xa_multi_store_adv(xa, pos + 157, i); } } #endif } -static noinline void check_xa_alloc_1(struct kunit *test, struct xarray *xa, unsigned int base) +static noinline void check_xa_alloc_1(struct xarray *xa, unsigned int base) { int i; u32 id; XA_BUG_ON(xa, !xa_empty(xa)); /* An empty array should assign %base to the first alloc */ - xa_alloc_index(test, xa, base, GFP_KERNEL); + xa_alloc_index(xa, base, GFP_KERNEL); /* Erasing it should make the array empty again */ - xa_erase_index(test, xa, base); + xa_erase_index(xa, base); XA_BUG_ON(xa, !xa_empty(xa)); /* And it should assign %base again */ - xa_alloc_index(test, xa, base, GFP_KERNEL); + xa_alloc_index(xa, base, GFP_KERNEL); /* Allocating and then erasing a lot should not lose base */ for (i = base + 1; i < 2 * XA_CHUNK_SIZE; i++) - xa_alloc_index(test, xa, i, GFP_KERNEL); + xa_alloc_index(xa, i, GFP_KERNEL); for (i = base; i < 2 * XA_CHUNK_SIZE; i++) - xa_erase_index(test, xa, i); - xa_alloc_index(test, xa, base, GFP_KERNEL); + xa_erase_index(xa, i); + xa_alloc_index(xa, base, GFP_KERNEL); /* Destroying the array should do the same as erasing */ xa_destroy(xa); /* And it should assign %base again */ - xa_alloc_index(test, xa, base, GFP_KERNEL); + xa_alloc_index(xa, base, GFP_KERNEL); /* The next assigned ID should be base+1 */ - xa_alloc_index(test, xa, base + 1, GFP_KERNEL); - xa_erase_index(test, xa, base + 1); + xa_alloc_index(xa, base + 1, GFP_KERNEL); + xa_erase_index(xa, base + 1); /* Storing a value should mark it used */ xa_store_index(xa, base + 1, GFP_KERNEL); - xa_alloc_index(test, xa, base + 2, GFP_KERNEL); + xa_alloc_index(xa, base + 2, GFP_KERNEL); /* If we then erase base, it should be free */ - xa_erase_index(test, xa, base); - xa_alloc_index(test, xa, base, GFP_KERNEL); + xa_erase_index(xa, base); + xa_alloc_index(xa, base, GFP_KERNEL); - xa_erase_index(test, xa, base + 1); - xa_erase_index(test, xa, base + 2); + xa_erase_index(xa, base + 1); + xa_erase_index(xa, base + 2); for (i = 1; i < 5000; i++) { - xa_alloc_index(test, xa, base + i, GFP_KERNEL); + xa_alloc_index(xa, base + i, GFP_KERNEL); } xa_destroy(xa); @@ -1016,14 +975,14 @@ static noinline void check_xa_alloc_1(struct kunit *test, struct xarray *xa, uns XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(10), XA_LIMIT(10, 5), GFP_KERNEL) != -EBUSY); - XA_BUG_ON(xa, xa_store_index(xa, 3, GFP_KERNEL) != NULL); + XA_BUG_ON(xa, xa_store_index(xa, 3, GFP_KERNEL) != 0); XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(10), XA_LIMIT(10, 5), GFP_KERNEL) != -EBUSY); - xa_erase_index(test, xa, 3); + xa_erase_index(xa, 3); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_xa_alloc_2(struct kunit *test, struct xarray *xa, unsigned int base) +static noinline void check_xa_alloc_2(struct xarray *xa, unsigned int base) { unsigned int i, id; unsigned long index; @@ -1059,7 +1018,7 @@ static noinline void check_xa_alloc_2(struct kunit *test, struct xarray *xa, uns XA_BUG_ON(xa, id != 5); xa_for_each(xa, index, entry) { - xa_erase_index(test, xa, index); + xa_erase_index(xa, index); } for (i = base; i < base + 9; i++) { @@ -1074,7 +1033,7 @@ static noinline void check_xa_alloc_2(struct kunit *test, struct xarray *xa, uns xa_destroy(xa); } -static noinline void check_xa_alloc_3(struct kunit *test, struct xarray *xa, unsigned int base) +static noinline void check_xa_alloc_3(struct xarray *xa, unsigned int base) { struct xa_limit limit = XA_LIMIT(1, 0x3fff); u32 next = 0; @@ -1090,8 +1049,8 @@ static noinline void check_xa_alloc_3(struct kunit *test, struct xarray *xa, uns XA_BUG_ON(xa, xa_alloc_cyclic(xa, &id, xa_mk_index(0x3ffd), limit, &next, GFP_KERNEL) != 0); XA_BUG_ON(xa, id != 0x3ffd); - xa_erase_index(test, xa, 0x3ffd); - xa_erase_index(test, xa, 1); + xa_erase_index(xa, 0x3ffd); + xa_erase_index(xa, 1); XA_BUG_ON(xa, !xa_empty(xa)); for (i = 0x3ffe; i < 0x4003; i++) { @@ -1106,8 +1065,8 @@ static noinline void check_xa_alloc_3(struct kunit *test, struct xarray *xa, uns /* Check wrap-around is handled correctly */ if (base != 0) - xa_erase_index(test, xa, base); - xa_erase_index(test, xa, base + 1); + xa_erase_index(xa, base); + xa_erase_index(xa, base + 1); next = UINT_MAX; XA_BUG_ON(xa, xa_alloc_cyclic(xa, &id, xa_mk_index(UINT_MAX), xa_limit_32b, &next, GFP_KERNEL) != 0); @@ -1120,7 +1079,7 @@ static noinline void check_xa_alloc_3(struct kunit *test, struct xarray *xa, uns XA_BUG_ON(xa, id != base + 1); xa_for_each(xa, index, entry) - xa_erase_index(test, xa, index); + xa_erase_index(xa, index); XA_BUG_ON(xa, !xa_empty(xa)); } @@ -1128,21 +1087,19 @@ static noinline void check_xa_alloc_3(struct kunit *test, struct xarray *xa, uns static DEFINE_XARRAY_ALLOC(xa0); static DEFINE_XARRAY_ALLOC1(xa1); -static noinline void check_xa_alloc(struct kunit *test) +static noinline void check_xa_alloc(void) { - check_xa_alloc_1(test, &xa0, 0); - check_xa_alloc_1(test, &xa1, 1); - check_xa_alloc_2(test, &xa0, 0); - check_xa_alloc_2(test, &xa1, 1); - check_xa_alloc_3(test, &xa0, 0); - check_xa_alloc_3(test, &xa1, 1); + check_xa_alloc_1(&xa0, 0); + check_xa_alloc_1(&xa1, 1); + check_xa_alloc_2(&xa0, 0); + check_xa_alloc_2(&xa1, 1); + check_xa_alloc_3(&xa0, 0); + check_xa_alloc_3(&xa1, 1); } -static noinline void __check_store_iter(struct kunit *test, unsigned long start, +static noinline void __check_store_iter(struct xarray *xa, unsigned long start, unsigned int order, unsigned int present) { - struct xarray *xa = xa_param(test); - XA_STATE_ORDER(xas, xa, start, order); void *entry; unsigned int count = 0; @@ -1166,54 +1123,50 @@ retry: XA_BUG_ON(xa, xa_load(xa, start) != xa_mk_index(start)); XA_BUG_ON(xa, xa_load(xa, start + (1UL << order) - 1) != xa_mk_index(start)); - xa_erase_index(test, xa, start); + xa_erase_index(xa, start); } -static noinline void check_store_iter(struct kunit *test) +static noinline void check_store_iter(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned int i, j; unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1; for (i = 0; i < max_order; i++) { unsigned int min = 1 << i; unsigned int max = (2 << i) - 1; - __check_store_iter(test, 0, i, 0); + __check_store_iter(xa, 0, i, 0); XA_BUG_ON(xa, !xa_empty(xa)); - __check_store_iter(test, min, i, 0); + __check_store_iter(xa, min, i, 0); XA_BUG_ON(xa, !xa_empty(xa)); xa_store_index(xa, min, GFP_KERNEL); - __check_store_iter(test, min, i, 1); + __check_store_iter(xa, min, i, 1); XA_BUG_ON(xa, !xa_empty(xa)); xa_store_index(xa, max, GFP_KERNEL); - __check_store_iter(test, min, i, 1); + __check_store_iter(xa, min, i, 1); XA_BUG_ON(xa, !xa_empty(xa)); for (j = 0; j < min; j++) xa_store_index(xa, j, GFP_KERNEL); - __check_store_iter(test, 0, i, min); + __check_store_iter(xa, 0, i, min); XA_BUG_ON(xa, !xa_empty(xa)); for (j = 0; j < min; j++) xa_store_index(xa, min + j, GFP_KERNEL); - __check_store_iter(test, min, i, min); + __check_store_iter(xa, min, i, min); XA_BUG_ON(xa, !xa_empty(xa)); } #ifdef CONFIG_XARRAY_MULTI xa_store_index(xa, 63, GFP_KERNEL); xa_store_index(xa, 65, GFP_KERNEL); - __check_store_iter(test, 64, 2, 1); - xa_erase_index(test, xa, 63); + __check_store_iter(xa, 64, 2, 1); + xa_erase_index(xa, 63); #endif XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_multi_find_1(struct kunit *test, unsigned int order) +static noinline void check_multi_find_1(struct xarray *xa, unsigned order) { #ifdef CONFIG_XARRAY_MULTI - struct xarray *xa = xa_param(test); - unsigned long multi = 3 << order; unsigned long next = 4 << order; unsigned long index; @@ -1236,17 +1189,15 @@ static noinline void check_multi_find_1(struct kunit *test, unsigned int order) XA_BUG_ON(xa, xa_find_after(xa, &index, next, XA_PRESENT) != NULL); XA_BUG_ON(xa, index != next); - xa_erase_index(test, xa, multi); - xa_erase_index(test, xa, next); - xa_erase_index(test, xa, next + 1); + xa_erase_index(xa, multi); + xa_erase_index(xa, next); + xa_erase_index(xa, next + 1); XA_BUG_ON(xa, !xa_empty(xa)); #endif } -static noinline void check_multi_find_2(struct kunit *test) +static noinline void check_multi_find_2(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 10 : 1; unsigned int i, j; void *entry; @@ -1260,19 +1211,17 @@ static noinline void check_multi_find_2(struct kunit *test) GFP_KERNEL); rcu_read_lock(); xas_for_each(&xas, entry, ULONG_MAX) { - xa_erase_index(test, xa, index); + xa_erase_index(xa, index); } rcu_read_unlock(); - xa_erase_index(test, xa, index - 1); + xa_erase_index(xa, index - 1); XA_BUG_ON(xa, !xa_empty(xa)); } } } -static noinline void check_multi_find_3(struct kunit *test) +static noinline void check_multi_find_3(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned int order; for (order = 5; order < order_limit; order++) { @@ -1281,14 +1230,12 @@ static noinline void check_multi_find_3(struct kunit *test) XA_BUG_ON(xa, !xa_empty(xa)); xa_store_order(xa, 0, order - 4, xa_mk_index(0), GFP_KERNEL); XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT)); - xa_erase_index(test, xa, 0); + xa_erase_index(xa, 0); } } -static noinline void check_find_1(struct kunit *test) +static noinline void check_find_1(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned long i, j, k; XA_BUG_ON(xa, !xa_empty(xa)); @@ -1325,20 +1272,18 @@ static noinline void check_find_1(struct kunit *test) else XA_BUG_ON(xa, entry != NULL); } - xa_erase_index(test, xa, j); + xa_erase_index(xa, j); XA_BUG_ON(xa, xa_get_mark(xa, j, XA_MARK_0)); XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0)); } - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_0)); } XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_find_2(struct kunit *test) +static noinline void check_find_2(struct xarray *xa) { - struct xarray *xa = xa_param(test); - void *entry; unsigned long i, j, index; @@ -1358,10 +1303,8 @@ static noinline void check_find_2(struct kunit *test) xa_destroy(xa); } -static noinline void check_find_3(struct kunit *test) +static noinline void check_find_3(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); unsigned long i, j, k; void *entry; @@ -1385,10 +1328,8 @@ static noinline void check_find_3(struct kunit *test) xa_destroy(xa); } -static noinline void check_find_4(struct kunit *test) +static noinline void check_find_4(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned long index = 0; void *entry; @@ -1400,22 +1341,22 @@ static noinline void check_find_4(struct kunit *test) entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT); XA_BUG_ON(xa, entry); - xa_erase_index(test, xa, ULONG_MAX); + xa_erase_index(xa, ULONG_MAX); } -static noinline void check_find(struct kunit *test) +static noinline void check_find(struct xarray *xa) { unsigned i; - check_find_1(test); - check_find_2(test); - check_find_3(test); - check_find_4(test); + check_find_1(xa); + check_find_2(xa); + check_find_3(xa); + check_find_4(xa); for (i = 2; i < 10; i++) - check_multi_find_1(test, i); - check_multi_find_2(test); - check_multi_find_3(test); + check_multi_find_1(xa, i); + check_multi_find_2(xa); + check_multi_find_3(xa); } /* See find_swap_entry() in mm/shmem.c */ @@ -1441,10 +1382,8 @@ static noinline unsigned long xa_find_entry(struct xarray *xa, void *item) return entry ? xas.xa_index : -1; } -static noinline void check_find_entry(struct kunit *test) +static noinline void check_find_entry(struct xarray *xa) { - struct xarray *xa = xa_param(test); - #ifdef CONFIG_XARRAY_MULTI unsigned int order; unsigned long offset, index; @@ -1471,14 +1410,12 @@ static noinline void check_find_entry(struct kunit *test) xa_store_index(xa, ULONG_MAX, GFP_KERNEL); XA_BUG_ON(xa, xa_find_entry(xa, xa) != -1); XA_BUG_ON(xa, xa_find_entry(xa, xa_mk_index(ULONG_MAX)) != -1); - xa_erase_index(test, xa, ULONG_MAX); + xa_erase_index(xa, ULONG_MAX); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_pause(struct kunit *test) +static noinline void check_pause(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); void *entry; unsigned int order; @@ -1548,10 +1485,8 @@ static noinline void check_pause(struct kunit *test) } -static noinline void check_move_tiny(struct kunit *test) +static noinline void check_move_tiny(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); XA_BUG_ON(xa, !xa_empty(xa)); @@ -1568,14 +1503,12 @@ static noinline void check_move_tiny(struct kunit *test) XA_BUG_ON(xa, xas_prev(&xas) != xa_mk_index(0)); XA_BUG_ON(xa, xas_prev(&xas) != NULL); rcu_read_unlock(); - xa_erase_index(test, xa, 0); + xa_erase_index(xa, 0); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_move_max(struct kunit *test) +static noinline void check_move_max(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); xa_store_index(xa, ULONG_MAX, GFP_KERNEL); @@ -1591,14 +1524,12 @@ static noinline void check_move_max(struct kunit *test) XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != NULL); rcu_read_unlock(); - xa_erase_index(test, xa, ULONG_MAX); + xa_erase_index(xa, ULONG_MAX); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_move_small(struct kunit *test, unsigned long idx) +static noinline void check_move_small(struct xarray *xa, unsigned long idx) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); unsigned long i; @@ -1640,15 +1571,13 @@ static noinline void check_move_small(struct kunit *test, unsigned long idx) XA_BUG_ON(xa, xas.xa_index != ULONG_MAX); rcu_read_unlock(); - xa_erase_index(test, xa, 0); - xa_erase_index(test, xa, idx); + xa_erase_index(xa, 0); + xa_erase_index(xa, idx); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_move(struct kunit *test) +static noinline void check_move(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, (1 << 16) - 1); unsigned long i; @@ -1675,7 +1604,7 @@ static noinline void check_move(struct kunit *test) rcu_read_unlock(); for (i = (1 << 8); i < (1 << 15); i++) - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); i = xas.xa_index; @@ -1706,17 +1635,17 @@ static noinline void check_move(struct kunit *test) xa_destroy(xa); - check_move_tiny(test); - check_move_max(test); + check_move_tiny(xa); + check_move_max(xa); for (i = 0; i < 16; i++) - check_move_small(test, 1UL << i); + check_move_small(xa, 1UL << i); for (i = 2; i < 16; i++) - check_move_small(test, (1UL << i) - 1); + check_move_small(xa, (1UL << i) - 1); } -static noinline void xa_store_many_order(struct kunit *test, struct xarray *xa, +static noinline void xa_store_many_order(struct xarray *xa, unsigned long index, unsigned order) { XA_STATE_ORDER(xas, xa, index, order); @@ -1739,34 +1668,30 @@ unlock: XA_BUG_ON(xa, xas_error(&xas)); } -static noinline void check_create_range_1(struct kunit *test, +static noinline void check_create_range_1(struct xarray *xa, unsigned long index, unsigned order) { - struct xarray *xa = xa_param(test); - unsigned long i; - xa_store_many_order(test, xa, index, order); + xa_store_many_order(xa, index, order); for (i = index; i < index + (1UL << order); i++) - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_create_range_2(struct kunit *test, unsigned int order) +static noinline void check_create_range_2(struct xarray *xa, unsigned order) { - struct xarray *xa = xa_param(test); - unsigned long i; unsigned long nr = 1UL << order; for (i = 0; i < nr * nr; i += nr) - xa_store_many_order(test, xa, i, order); + xa_store_many_order(xa, i, order); for (i = 0; i < nr * nr; i++) - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_create_range_3(struct kunit *test) +static noinline void check_create_range_3(void) { XA_STATE(xas, NULL, 0); xas_set_err(&xas, -EEXIST); @@ -1774,11 +1699,9 @@ static noinline void check_create_range_3(struct kunit *test) XA_BUG_ON(NULL, xas_error(&xas) != -EEXIST); } -static noinline void check_create_range_4(struct kunit *test, +static noinline void check_create_range_4(struct xarray *xa, unsigned long index, unsigned order) { - struct xarray *xa = xa_param(test); - XA_STATE_ORDER(xas, xa, index, order); unsigned long base = xas.xa_index; unsigned long i = 0; @@ -1804,15 +1727,13 @@ unlock: XA_BUG_ON(xa, xas_error(&xas)); for (i = base; i < base + (1UL << order); i++) - xa_erase_index(test, xa, i); + xa_erase_index(xa, i); XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_create_range_5(struct kunit *test, +static noinline void check_create_range_5(struct xarray *xa, unsigned long index, unsigned int order) { - struct xarray *xa = xa_param(test); - XA_STATE_ORDER(xas, xa, index, order); unsigned int i; @@ -1829,46 +1750,44 @@ static noinline void check_create_range_5(struct kunit *test, xa_destroy(xa); } -static noinline void check_create_range(struct kunit *test) +static noinline void check_create_range(struct xarray *xa) { unsigned int order; unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 12 : 1; for (order = 0; order < max_order; order++) { - check_create_range_1(test, 0, order); - check_create_range_1(test, 1U << order, order); - check_create_range_1(test, 2U << order, order); - check_create_range_1(test, 3U << order, order); - check_create_range_1(test, 1U << 24, order); + check_create_range_1(xa, 0, order); + check_create_range_1(xa, 1U << order, order); + check_create_range_1(xa, 2U << order, order); + check_create_range_1(xa, 3U << order, order); + check_create_range_1(xa, 1U << 24, order); if (order < 10) - check_create_range_2(test, order); - - check_create_range_4(test, 0, order); - check_create_range_4(test, 1U << order, order); - check_create_range_4(test, 2U << order, order); - check_create_range_4(test, 3U << order, order); - check_create_range_4(test, 1U << 24, order); - - check_create_range_4(test, 1, order); - check_create_range_4(test, (1U << order) + 1, order); - check_create_range_4(test, (2U << order) + 1, order); - check_create_range_4(test, (2U << order) - 1, order); - check_create_range_4(test, (3U << order) + 1, order); - check_create_range_4(test, (3U << order) - 1, order); - check_create_range_4(test, (1U << 24) + 1, order); - - check_create_range_5(test, 0, order); - check_create_range_5(test, (1U << order), order); + check_create_range_2(xa, order); + + check_create_range_4(xa, 0, order); + check_create_range_4(xa, 1U << order, order); + check_create_range_4(xa, 2U << order, order); + check_create_range_4(xa, 3U << order, order); + check_create_range_4(xa, 1U << 24, order); + + check_create_range_4(xa, 1, order); + check_create_range_4(xa, (1U << order) + 1, order); + check_create_range_4(xa, (2U << order) + 1, order); + check_create_range_4(xa, (2U << order) - 1, order); + check_create_range_4(xa, (3U << order) + 1, order); + check_create_range_4(xa, (3U << order) - 1, order); + check_create_range_4(xa, (1U << 24) + 1, order); + + check_create_range_5(xa, 0, order); + check_create_range_5(xa, (1U << order), order); } - check_create_range_3(test); + check_create_range_3(); } -static noinline void __check_store_range(struct kunit *test, unsigned long first, +static noinline void __check_store_range(struct xarray *xa, unsigned long first, unsigned long last) { - struct xarray *xa = xa_param(test); - #ifdef CONFIG_XARRAY_MULTI xa_store_range(xa, first, last, xa_mk_index(first), GFP_KERNEL); @@ -1883,28 +1802,26 @@ static noinline void __check_store_range(struct kunit *test, unsigned long first XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_store_range(struct kunit *test) +static noinline void check_store_range(struct xarray *xa) { unsigned long i, j; for (i = 0; i < 128; i++) { for (j = i; j < 128; j++) { - __check_store_range(test, i, j); - __check_store_range(test, 128 + i, 128 + j); - __check_store_range(test, 4095 + i, 4095 + j); - __check_store_range(test, 4096 + i, 4096 + j); - __check_store_range(test, 123456 + i, 123456 + j); - __check_store_range(test, (1 << 24) + i, (1 << 24) + j); + __check_store_range(xa, i, j); + __check_store_range(xa, 128 + i, 128 + j); + __check_store_range(xa, 4095 + i, 4095 + j); + __check_store_range(xa, 4096 + i, 4096 + j); + __check_store_range(xa, 123456 + i, 123456 + j); + __check_store_range(xa, (1 << 24) + i, (1 << 24) + j); } } } #ifdef CONFIG_XARRAY_MULTI -static void check_split_1(struct kunit *test, unsigned long index, +static void check_split_1(struct xarray *xa, unsigned long index, unsigned int order, unsigned int new_order) { - struct xarray *xa = xa_param(test); - XA_STATE_ORDER(xas, xa, index, new_order); unsigned int i, found; void *entry; @@ -1940,30 +1857,26 @@ static void check_split_1(struct kunit *test, unsigned long index, xa_destroy(xa); } -static noinline void check_split(struct kunit *test) +static noinline void check_split(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned int order, new_order; XA_BUG_ON(xa, !xa_empty(xa)); for (order = 1; order < 2 * XA_CHUNK_SHIFT; order++) { for (new_order = 0; new_order < order; new_order++) { - check_split_1(test, 0, order, new_order); - check_split_1(test, 1UL << order, order, new_order); - check_split_1(test, 3UL << order, order, new_order); + check_split_1(xa, 0, order, new_order); + check_split_1(xa, 1UL << order, order, new_order); + check_split_1(xa, 3UL << order, order, new_order); } } } #else -static void check_split(struct kunit *test) { } +static void check_split(struct xarray *xa) { } #endif -static void check_align_1(struct kunit *test, char *name) +static void check_align_1(struct xarray *xa, char *name) { - struct xarray *xa = xa_param(test); - int i; unsigned int id; unsigned long index; @@ -1983,10 +1896,8 @@ static void check_align_1(struct kunit *test, char *name) * We should always be able to store without allocating memory after * reserving a slot. */ -static void check_align_2(struct kunit *test, char *name) +static void check_align_2(struct xarray *xa, char *name) { - struct xarray *xa = xa_param(test); - int i; XA_BUG_ON(xa, !xa_empty(xa)); @@ -2005,15 +1916,15 @@ static void check_align_2(struct kunit *test, char *name) XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_align(struct kunit *test) +static noinline void check_align(struct xarray *xa) { char name[] = "Motorola 68000"; - check_align_1(test, name); - check_align_1(test, name + 1); - check_align_1(test, name + 2); - check_align_1(test, name + 3); - check_align_2(test, name); + check_align_1(xa, name); + check_align_1(xa, name + 1); + check_align_1(xa, name + 2); + check_align_1(xa, name + 3); + check_align_2(xa, name); } static LIST_HEAD(shadow_nodes); @@ -2029,7 +1940,7 @@ static void test_update_node(struct xa_node *node) } } -static noinline void shadow_remove(struct kunit *test, struct xarray *xa) +static noinline void shadow_remove(struct xarray *xa) { struct xa_node *node; @@ -2043,17 +1954,8 @@ static noinline void shadow_remove(struct kunit *test, struct xarray *xa) xa_unlock(xa); } -struct workingset_testcase { - struct xarray *xa; - unsigned long index; -}; - -static noinline void check_workingset(struct kunit *test) +static noinline void check_workingset(struct xarray *xa, unsigned long index) { - struct workingset_testcase tc = *(struct workingset_testcase *)test->param_value; - struct xarray *xa = tc.xa; - unsigned long index = tc.index; - XA_STATE(xas, xa, index); xas_set_update(&xas, test_update_node); @@ -2076,7 +1978,7 @@ static noinline void check_workingset(struct kunit *test) xas_unlock(&xas); XA_BUG_ON(xa, list_empty(&shadow_nodes)); - shadow_remove(test, xa); + shadow_remove(xa); XA_BUG_ON(xa, !list_empty(&shadow_nodes)); XA_BUG_ON(xa, !xa_empty(xa)); } @@ -2085,11 +1987,9 @@ static noinline void check_workingset(struct kunit *test) * Check that the pointer / value / sibling entries are accounted the * way we expect them to be. */ -static noinline void check_account(struct kunit *test) +static noinline void check_account(struct xarray *xa) { #ifdef CONFIG_XARRAY_MULTI - struct xarray *xa = xa_param(test); - unsigned int order; for (order = 1; order < 12; order++) { @@ -2116,10 +2016,8 @@ static noinline void check_account(struct kunit *test) #endif } -static noinline void check_get_order(struct kunit *test) +static noinline void check_get_order(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1; unsigned int order; unsigned long i, j; @@ -2138,10 +2036,8 @@ static noinline void check_get_order(struct kunit *test) } } -static noinline void check_xas_get_order(struct kunit *test) +static noinline void check_xas_get_order(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1; @@ -2173,10 +2069,8 @@ static noinline void check_xas_get_order(struct kunit *test) } } -static noinline void check_xas_conflict_get_order(struct kunit *test) +static noinline void check_xas_conflict_get_order(struct xarray *xa) { - struct xarray *xa = xa_param(test); - XA_STATE(xas, xa, 0); void *entry; @@ -2233,10 +2127,8 @@ static noinline void check_xas_conflict_get_order(struct kunit *test) } -static noinline void check_destroy(struct kunit *test) +static noinline void check_destroy(struct xarray *xa) { - struct xarray *xa = xa_param(test); - unsigned long index; XA_BUG_ON(xa, !xa_empty(xa)); @@ -2269,59 +2161,52 @@ static noinline void check_destroy(struct kunit *test) } static DEFINE_XARRAY(array); -static struct xarray *arrays[] = { &array }; -KUNIT_ARRAY_PARAM(array, arrays, NULL); - -static struct xarray *xa0s[] = { &xa0 }; -KUNIT_ARRAY_PARAM(xa0, xa0s, NULL); - -static struct workingset_testcase workingset_testcases[] = { - { &array, 0 }, - { &array, 64 }, - { &array, 4096 }, -}; -KUNIT_ARRAY_PARAM(workingset, workingset_testcases, NULL); - -static struct kunit_case xarray_cases[] = { - KUNIT_CASE_PARAM(check_xa_err, array_gen_params), - KUNIT_CASE_PARAM(check_xas_retry, array_gen_params), - KUNIT_CASE_PARAM(check_xa_load, array_gen_params), - KUNIT_CASE_PARAM(check_xa_mark, array_gen_params), - KUNIT_CASE_PARAM(check_xa_shrink, array_gen_params), - KUNIT_CASE_PARAM(check_xas_erase, array_gen_params), - KUNIT_CASE_PARAM(check_insert, array_gen_params), - KUNIT_CASE_PARAM(check_cmpxchg, array_gen_params), - KUNIT_CASE_PARAM(check_cmpxchg_order, array_gen_params), - KUNIT_CASE_PARAM(check_reserve, array_gen_params), - KUNIT_CASE_PARAM(check_reserve, xa0_gen_params), - KUNIT_CASE_PARAM(check_multi_store, array_gen_params), - KUNIT_CASE_PARAM(check_multi_store_advanced, array_gen_params), - KUNIT_CASE_PARAM(check_get_order, array_gen_params), - KUNIT_CASE_PARAM(check_xas_get_order, array_gen_params), - KUNIT_CASE_PARAM(check_xas_conflict_get_order, array_gen_params), - KUNIT_CASE(check_xa_alloc), - KUNIT_CASE_PARAM(check_find, array_gen_params), - KUNIT_CASE_PARAM(check_find_entry, array_gen_params), - KUNIT_CASE_PARAM(check_pause, array_gen_params), - KUNIT_CASE_PARAM(check_account, array_gen_params), - KUNIT_CASE_PARAM(check_destroy, array_gen_params), - KUNIT_CASE_PARAM(check_move, array_gen_params), - KUNIT_CASE_PARAM(check_create_range, array_gen_params), - KUNIT_CASE_PARAM(check_store_range, array_gen_params), - KUNIT_CASE_PARAM(check_store_iter, array_gen_params), - KUNIT_CASE_PARAM(check_align, xa0_gen_params), - KUNIT_CASE_PARAM(check_split, array_gen_params), - KUNIT_CASE_PARAM(check_workingset, workingset_gen_params), - {}, -}; - -static struct kunit_suite xarray_suite = { - .name = "xarray", - .test_cases = xarray_cases, -}; - -kunit_test_suite(xarray_suite); +static int xarray_checks(void) +{ + check_xa_err(&array); + check_xas_retry(&array); + check_xa_load(&array); + check_xa_mark(&array); + check_xa_shrink(&array); + check_xas_erase(&array); + check_insert(&array); + check_cmpxchg(&array); + check_cmpxchg_order(&array); + check_reserve(&array); + check_reserve(&xa0); + check_multi_store(&array); + check_multi_store_advanced(&array); + check_get_order(&array); + check_xas_get_order(&array); + check_xas_conflict_get_order(&array); + check_xa_alloc(); + check_find(&array); + check_find_entry(&array); + check_pause(&array); + check_account(&array); + check_destroy(&array); + check_move(&array); + check_create_range(&array); + check_store_range(&array); + check_store_iter(&array); + check_align(&xa0); + check_split(&array); + + check_workingset(&array, 0); + check_workingset(&array, 64); + check_workingset(&array, 4096); + + printk("XArray: %u of %u tests passed\n", tests_passed, tests_run); + return (tests_run == tests_passed) ? 0 : -EINVAL; +} + +static void xarray_exit(void) +{ +} + +module_init(xarray_checks); +module_exit(xarray_exit); MODULE_AUTHOR("Matthew Wilcox "); MODULE_DESCRIPTION("XArray API test module"); MODULE_LICENSE("GPL"); -- 2.51.0 From e5b2a356dc8a88708d97bd47cca3b8f7ed7af6cb Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 30 Jan 2025 16:16:20 -0800 Subject: [PATCH 04/16] MAINTAINERS: include linux-mm for xarray maintenance MM developers have an interest in the xarray code. Cc: David Gow Cc: Geert Uytterhoeven Cc: "Liam R. Howlett" Cc: Lorenzo Stoakes Cc: Matthew Wilcox Cc: Sidhartha Kumar Cc: Tamir Duberstein Signed-off-by: Andrew Morton --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f52a004982c9..ab7463b2f165 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25729,6 +25729,7 @@ F: arch/x86/entry/vdso/ XARRAY M: Matthew Wilcox L: linux-fsdevel@vger.kernel.org +L: linux-mm@kvack.org S: Supported F: Documentation/core-api/xarray.rst F: include/linux/idr.h -- 2.51.0 From 2c4627c8ced77855b106c7104ecab70837d53799 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 2 Feb 2025 10:43:02 -0600 Subject: [PATCH 05/16] tools/power turbostat: version 2025.02.02 Summary of Changes since 2024.11.30: Fix regression in 2023.11.07 that affinitized forked child in one-shot mode. Harden one-shot mode against hotplug online/offline Enable RAPL SysWatt column by default. Add initial PTL, CWF platform support. Harden initial PMT code in response to early use. Enable first built-in PMT counter: CWF c1e residency Refuse to run on unsupported platforms without --force, to encourage updating to a version that supports the system, and to avoid no-so-useful measurement results. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 364a44a7d7ae..8d5011a0bf60 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9559,7 +9559,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2025.01.14 - Len Brown \n"); + fprintf(outf, "turbostat version 2025.02.02 - Len Brown \n"); } #define COMMAND_LINE_SIZE 2048 -- 2.51.0 From 2014c95afecee3e76ca4a56956a936e23283f05b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 2 Feb 2025 15:39:26 -0800 Subject: [PATCH 06/16] Linux 6.14-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4117cc79748b..9e0d63d9d94b 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 13 +PATCHLEVEL = 14 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION* -- 2.51.0 From 76b0a22d4cf7dc9091129560fdc04e73eb9db4cb Mon Sep 17 00:00:00 2001 From: Edson Juliano Drosdeck Date: Sat, 1 Feb 2025 11:39:30 -0300 Subject: [PATCH 07/16] ALSA: hda/realtek: Limit mic boost on Positivo ARN50 The internal mic boost on the Positivo ARN50 is too high. Fix this by applying the ALC269_FIXUP_LIMIT_INT_MIC_BOOST fixup to the machine to limit the gain. Signed-off-by: Edson Juliano Drosdeck Link: https://patch.msgid.link/20250201143930.25089-1-edson.drosdeck@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8192be394d0d..ae0beb52e7b0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11045,6 +11045,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13), SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), -- 2.51.0 From e8d04a92484e6504bb0c98426db54bfc82a6934f Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 22 Jan 2025 02:20:59 +0000 Subject: [PATCH 08/16] ALSA: lola: Remove unused lola_(save|restore)_mixer lola_restore_mixer() and lola_save_mixer() were added in 2011 by commit d43f3010b8fa ("ALSA: Add the driver for Digigram Lola PCI-e boards") but have remain unused. Remove them. Signed-off-by: Dr. David Alan Gilbert Link: https://patch.msgid.link/20250122022059.456068-1-linux@treblig.org Signed-off-by: Takashi Iwai --- sound/pci/lola/lola.h | 2 -- sound/pci/lola/lola_mixer.c | 43 ------------------------------------- 2 files changed, 45 deletions(-) diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h index 0ff772cf66e6..25f72f9e3f9b 100644 --- a/sound/pci/lola/lola.h +++ b/sound/pci/lola/lola.h @@ -499,8 +499,6 @@ int lola_init_mixer_widget(struct lola *chip, int nid); void lola_free_mixer(struct lola *chip); int lola_create_mixer(struct lola *chip); int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute); -void lola_save_mixer(struct lola *chip); -void lola_restore_mixer(struct lola *chip); int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update); /* proc */ diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 6b162489cb5f..9cb26a8a4e1a 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -336,49 +336,6 @@ int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute) return lola_codec_flush(chip); } -void lola_save_mixer(struct lola *chip) -{ - /* mute analog output */ - if (chip->mixer.array_saved) { - /* store contents of mixer array */ - memcpy_fromio(chip->mixer.array_saved, chip->mixer.array, - sizeof(*chip->mixer.array)); - } - lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */ -} - -void lola_restore_mixer(struct lola *chip) -{ - int i; - - /*lola_reset_setups(chip);*/ - if (chip->mixer.array_saved) { - /* restore contents of mixer array */ - memcpy_toio(chip->mixer.array, chip->mixer.array_saved, - sizeof(*chip->mixer.array)); - /* inform micro-controller about all restored values - * and ignore return values - */ - for (i = 0; i < chip->mixer.src_phys_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - i, 0); - for (i = 0; i < chip->mixer.src_stream_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - chip->mixer.src_stream_out_ofs + i, 0); - for (i = 0; i < chip->mixer.dest_stream_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - i, 0); - for (i = 0; i < chip->mixer.dest_phys_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - chip->mixer.dest_phys_out_ofs + i, 0); - lola_codec_flush(chip); - } -} - /* */ -- 2.51.0 From 1b0e9d7f76c9bb6bd1a345ef033ae7fe5e77649c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 24 Jan 2025 23:14:30 +0200 Subject: [PATCH 09/16] ALSA: hda/hdmi: extract common interface for ELD handling Other HDMI-related cards (e.g. hdmi-codec) are also using the ELD. Exrtact common set of interfaces for handling the ELD. Signed-off-by: Dmitry Baryshkov Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250124-alsa-hdmi-codec-eld-v1-1-bad045cfaeac@linaro.org --- include/sound/pcm_drm_eld.h | 91 +++++++++ sound/core/pcm_drm_eld.c | 387 ++++++++++++++++++++++++++++++++++++ sound/pci/hda/Kconfig | 1 + sound/pci/hda/hda_eld.c | 385 +---------------------------------- sound/pci/hda/hda_local.h | 49 +---- sound/pci/hda/patch_hdmi.c | 6 +- 6 files changed, 494 insertions(+), 425 deletions(-) diff --git a/include/sound/pcm_drm_eld.h b/include/sound/pcm_drm_eld.h index 28a55a8beb28..5a38413ada91 100644 --- a/include/sound/pcm_drm_eld.h +++ b/include/sound/pcm_drm_eld.h @@ -2,6 +2,97 @@ #ifndef __SOUND_PCM_DRM_ELD_H #define __SOUND_PCM_DRM_ELD_H +enum eld_versions { + ELD_VER_CEA_861D = 2, + ELD_VER_PARTIAL = 31, +}; + +enum cea_audio_coding_types { + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, + AUDIO_CODING_TYPE_LPCM = 1, + AUDIO_CODING_TYPE_AC3 = 2, + AUDIO_CODING_TYPE_MPEG1 = 3, + AUDIO_CODING_TYPE_MP3 = 4, + AUDIO_CODING_TYPE_MPEG2 = 5, + AUDIO_CODING_TYPE_AACLC = 6, + AUDIO_CODING_TYPE_DTS = 7, + AUDIO_CODING_TYPE_ATRAC = 8, + AUDIO_CODING_TYPE_SACD = 9, + AUDIO_CODING_TYPE_EAC3 = 10, + AUDIO_CODING_TYPE_DTS_HD = 11, + AUDIO_CODING_TYPE_MLP = 12, + AUDIO_CODING_TYPE_DST = 13, + AUDIO_CODING_TYPE_WMAPRO = 14, + AUDIO_CODING_TYPE_REF_CXT = 15, + /* also include valid xtypes below */ + AUDIO_CODING_TYPE_HE_AAC = 15, + AUDIO_CODING_TYPE_HE_AAC2 = 16, + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, +}; + +enum cea_audio_coding_xtypes { + AUDIO_CODING_XTYPE_HE_REF_CT = 0, + AUDIO_CODING_XTYPE_HE_AAC = 1, + AUDIO_CODING_XTYPE_HE_AAC2 = 2, + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, +}; + +/* + * CEA Short Audio Descriptor data + */ +struct snd_cea_sad { + int channels; + int format; /* (format == 0) indicates invalid SAD */ + int rates; + int sample_bits; /* for LPCM */ + int max_bitrate; /* for AC3...ATRAC */ + int profile; /* for WMAPRO */ +}; + +#define ELD_FIXED_BYTES 20 +#define ELD_MAX_SIZE 256 +#define ELD_MAX_MNL 16 +#define ELD_MAX_SAD 16 + +#define ELD_PCM_BITS_8 BIT(0) +#define ELD_PCM_BITS_16 BIT(1) +#define ELD_PCM_BITS_20 BIT(2) +#define ELD_PCM_BITS_24 BIT(3) +#define ELD_PCM_BITS_32 BIT(4) + +/* + * ELD: EDID Like Data + */ +struct snd_parsed_hdmi_eld { + /* + * all fields will be cleared before updating ELD + */ + int baseline_len; + int eld_ver; + int cea_edid_ver; + char monitor_name[ELD_MAX_MNL + 1]; + int manufacture_id; + int product_id; + u64 port_id; + int support_hdcp; + int support_ai; + int conn_type; + int aud_synch_delay; + int spk_alloc; + int sad_count; + struct snd_cea_sad sad[ELD_MAX_SAD]; +}; + int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld); +int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e, + const unsigned char *buf, int size); +void snd_show_eld(struct device *dev, struct snd_parsed_hdmi_eld *e); + +#ifdef CONFIG_SND_PROC_FS +void snd_print_eld_info(struct snd_parsed_hdmi_eld *eld, + struct snd_info_buffer *buffer); +#endif + #endif diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index 1cdca4d4fc9c..688eefce82fa 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -5,8 +5,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -162,3 +164,388 @@ int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld) return ret; } EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld); + +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 +#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 + +static const char * const eld_connection_type_names[4] = { + "HDMI", + "DisplayPort", + "2-reserved", + "3-reserved" +}; + +static const char * const cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD (One Bit Audio)", + /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", + /* 11 */ "DTS-HD", + /* 12 */ "MLP (Dolby TrueHD)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + +static const char * const cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +/* + * SS1:SS0 index => sample size + */ +static const int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + ELD_PCM_BITS_16, /* 1: 16 bits */ + ELD_PCM_BITS_20, /* 2: 20 bits */ + ELD_PCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static const int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +#define GRAB_BITS(buf, byte, lowbit, bits) \ +({ \ + BUILD_BUG_ON(lowbit > 7); \ + BUILD_BUG_ON(bits > 8); \ + BUILD_BUG_ON(bits <= 0); \ + \ + (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ +}) + +static void hdmi_update_short_audio_desc(struct device *dev, + struct snd_cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = GRAB_BITS(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = GRAB_BITS(buf, 0, 0, 3); + a->channels++; + + a->sample_bits = 0; + a->max_bitrate = 0; + + a->format = GRAB_BITS(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + dev_info(dev, "HDMI: audio coding type 0 not expected\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = GRAB_BITS(buf, 2, 0, 3); + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = GRAB_BITS(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = GRAB_BITS(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + dev_info(dev, + "HDMI: audio coding xtype %d not expected\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e, + const unsigned char *buf, int size) +{ + int mnl; + int i; + + memset(e, 0, sizeof(*e)); + e->eld_ver = GRAB_BITS(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + dev_info(dev, "HDMI: Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->baseline_len = GRAB_BITS(buf, 2, 0, 8); + mnl = GRAB_BITS(buf, 4, 0, 5); + e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); + + e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); + e->support_ai = GRAB_BITS(buf, 5, 1, 1); + e->conn_type = GRAB_BITS(buf, 5, 2, 2); + e->sad_count = GRAB_BITS(buf, 5, 4, 4); + + e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; + e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + dev_info(dev, "HDMI: MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + dev_info(dev, "HDMI: out of range MNL %d\n", mnl); + goto out_fail; + } else + strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + dev_info(dev, "HDMI: out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(dev, e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!e->spk_alloc) + e->spk_alloc = 0xffff; + + return 0; + +out_fail: + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_parse_eld); + +/* + * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with + * hdmi-specific routine. + */ +static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) +{ + static const unsigned int alsa_rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000, 384000 + }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) + if (pcm & (1 << i)) + j += scnprintf(buf + j, buflen - j, " %d", + alsa_rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void eld_print_pcm_bits(int pcm, char *buf, int buflen) +{ + static const unsigned int bits[] = { 8, 16, 20, 24, 32 }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (ELD_PCM_BITS_8 << i)) + j += scnprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void hdmi_show_short_audio_desc(struct device *dev, + struct snd_cea_sad *a) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; + + if (!a->format) + return; + + hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + eld_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); + else if (a->max_bitrate) + snprintf(buf2, sizeof(buf2), + ", max bitrate = %d", a->max_bitrate); + else + buf2[0] = '\0'; + + dev_dbg(dev, + "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, buf, buf2); +} + +static void snd_eld_print_channel_allocation(int spk_alloc, char *buf, int buflen) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (spk_alloc & (1 << i)) + j += scnprintf(buf + j, buflen - j, " %s", + cea_speaker_allocation_names[i]); + } + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_show_eld(struct device *dev, struct snd_parsed_hdmi_eld *e) +{ + int i; + + dev_dbg(dev, "HDMI: detected monitor %s at connection type %s\n", + e->monitor_name, + eld_connection_type_names[e->conn_type]); + + if (e->spk_alloc) { + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + dev_dbg(dev, "HDMI: available speakers:%s\n", buf); + } + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(dev, e->sad + i); +} +EXPORT_SYMBOL_GPL(snd_show_eld); + +#ifdef CONFIG_SND_PROC_FS +static void hdmi_print_sad_info(int i, struct snd_cea_sad *a, + struct snd_info_buffer *buffer) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + + snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", + i, a->format, cea_audio_coding_type_names[a->format]); + snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); + + hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) { + eld_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", + i, a->sample_bits, buf); + } + + if (a->max_bitrate) + snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", + i, a->max_bitrate); + + if (a->profile) + snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); +} + +void snd_print_eld_info(struct snd_parsed_hdmi_eld *e, + struct snd_info_buffer *buffer) +{ + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + int i; + static const char * const eld_version_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" + }; + static const char * const cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" + }; + + snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "connection_type\t\t%s\n", + eld_connection_type_names[e->conn_type]); + snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, + eld_version_names[e->eld_ver]); + snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, + cea_edid_version_names[e->cea_edid_ver]); + snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); + snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); + snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); + snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); + snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); + snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); + + snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); + + snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); + + for (i = 0; i < e->sad_count; i++) + hdmi_print_sad_info(i, e->sad + i, buffer); +} +EXPORT_SYMBOL_GPL(snd_print_eld_info); +#endif /* CONFIG_SND_PROC_FS */ diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index e393578cbe68..9f68cb73b54f 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -266,6 +266,7 @@ comment "Set to Y if you want auto-loading the codec driver" config SND_HDA_CODEC_HDMI tristate "Build HDMI/DisplayPort HD-audio codec support" select SND_DYNAMIC_MINORS + select SND_PCM_ELD help Say Y or M here to include HDMI and DisplayPort HD-audio codec support in snd-hda-intel driver. This includes all AMD/ATI, diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 301730432375..d3e87b9c1a4f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -17,11 +17,6 @@ #include #include "hda_local.h" -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - enum cea_edid_versions { CEA_EDID_VER_NONE = 0, CEA_EDID_VER_CEA861 = 1, @@ -30,95 +25,12 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static const char * const eld_connection_type_names[4] = { - "HDMI", - "DisplayPort", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static const char * const cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD (One Bit Audio)", - /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", - /* 11 */ "DTS-HD", - /* 12 */ "MLP (Dolby TrueHD)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - /* * The following two lists are shared between * - HDMI audio InfoFrame (source to sink) * - CEA E-EDID Extension (sink to source) */ -/* - * SS1:SS0 index => sample size - */ -static const int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static const int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, int byte_index) { @@ -132,159 +44,6 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, return val; } -#define GRAB_BITS(buf, byte, lowbit, bits) \ -({ \ - BUILD_BUG_ON(lowbit > 7); \ - BUILD_BUG_ON(bits > 8); \ - BUILD_BUG_ON(bits <= 0); \ - \ - (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ -}) - -static void hdmi_update_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = GRAB_BITS(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = GRAB_BITS(buf, 0, 0, 3); - a->channels++; - - a->sample_bits = 0; - a->max_bitrate = 0; - - a->format = GRAB_BITS(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - codec_info(codec, "HDMI: audio coding type 0 not expected\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = GRAB_BITS(buf, 2, 0, 3); - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = GRAB_BITS(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = GRAB_BITS(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - codec_info(codec, - "HDMI: audio coding xtype %d not expected\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size) -{ - int mnl; - int i; - - memset(e, 0, sizeof(*e)); - e->eld_ver = GRAB_BITS(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); - goto out_fail; - } - - e->baseline_len = GRAB_BITS(buf, 2, 0, 8); - mnl = GRAB_BITS(buf, 4, 0, 5); - e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); - - e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); - e->support_ai = GRAB_BITS(buf, 5, 1, 1); - e->conn_type = GRAB_BITS(buf, 5, 2, 2); - e->sad_count = GRAB_BITS(buf, 5, 4, 4); - - e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; - e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - codec_info(codec, "HDMI: out of range MNL %d\n", mnl); - goto out_fail; - } else - strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - codec_info(codec, "HDMI: out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(codec, e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!e->spk_alloc) - e->spk_alloc = 0xffff; - - return 0; - -out_fail: - return -EINVAL; -} - int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -346,155 +105,27 @@ error: return ret; } -/* - * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with - * hdmi-specific routine. - */ -static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static const unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) - if (pcm & (1 << i)) - j += scnprintf(buf + j, buflen - j, " %d", - alsa_rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - -#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 - -static void hdmi_show_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - - if (!a->format) - return; - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); - else if (a->max_bitrate) - snprintf(buf2, sizeof(buf2), - ", max bitrate = %d", a->max_bitrate); - else - buf2[0] = '\0'; - - codec_dbg(codec, - "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, buf, buf2); -} - -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) -{ - int i; - - codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", - e->monitor_name, - eld_connection_type_names[e->conn_type]); - - if (e->spk_alloc) { - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - codec_dbg(codec, "HDMI: available speakers:%s\n", buf); - } - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(codec, e->sad + i); -} - #ifdef CONFIG_SND_PROC_FS - -static void hdmi_print_sad_info(int i, struct cea_sad *a, - struct snd_info_buffer *buffer) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - - snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", - i, a->format, cea_audio_coding_type_names[a->format]); - snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - - if (a->format == AUDIO_CODING_TYPE_LPCM) { - snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", - i, a->sample_bits, buf); - } - - if (a->max_bitrate) - snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", - i, a->max_bitrate); - - if (a->profile) - snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); -} - void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer, hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) { - struct parsed_hdmi_eld *e = &eld->info; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - int i; - static const char * const eld_version_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" - }; - static const char * const cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" - }; - snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid); snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id); snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid); + if (!eld->eld_valid) return; - snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); - snd_iprintf(buffer, "connection_type\t\t%s\n", - eld_connection_type_names[e->conn_type]); - snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, - eld_version_names[e->eld_ver]); - snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, - cea_edid_version_names[e->cea_edid_ver]); - snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); - snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); - snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); - snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); - snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); - snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); - - snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); - - for (i = 0; i < e->sad_count; i++) - hdmi_print_sad_info(i, e->sad + i, buffer); + + snd_print_eld_info(&eld->info, buffer); } void snd_hdmi_write_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer) { - struct parsed_hdmi_eld *e = &eld->info; + struct snd_parsed_hdmi_eld *e = &eld->info; char line[64]; char name[64]; char *sname; @@ -556,7 +187,7 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, #endif /* CONFIG_SND_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo) { u32 rates; @@ -574,17 +205,17 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, maxbps = 16; channels_max = 2; for (i = 0; i < e->sad_count; i++) { - struct cea_sad *a = &e->sad[i]; + struct snd_cea_sad *a = &e->sad[i]; rates |= a->rates; if (a->channels > channels_max) channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { - if (a->sample_bits & AC_SUPPCM_BITS_20) { + if (a->sample_bits & ELD_PCM_BITS_20) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 20) maxbps = 20; } - if (a->sample_bits & AC_SUPPCM_BITS_24) { + if (a->sample_bits & ELD_PCM_BITS_24) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 24) maxbps = 24; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 763f79f6f32e..4714057dba85 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -10,6 +10,8 @@ #ifndef __SOUND_HDA_LOCAL_H #define __SOUND_HDA_LOCAL_H +#include + /* We abuse kcontrol_new.subdev field to pass the NID corresponding to * the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG, * snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID. @@ -675,61 +677,18 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, #define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_SIZE 256 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct parsed_hdmi_eld { - /* - * all fields will be cleared before updating ELD - */ - int baseline_len; - int eld_ver; - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -}; - struct hdmi_eld { bool monitor_present; bool eld_valid; int eld_size; char eld_buffer[ELD_MAX_SIZE]; - struct parsed_hdmi_eld info; + struct snd_parsed_hdmi_eld info; }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 643e0496b093..7167989a8d86 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1511,8 +1511,8 @@ static void update_eld(struct hda_codec *codec, if (eld->eld_valid) { if (eld->eld_size <= 0 || - snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, - eld->eld_size) < 0) { + snd_parse_eld(hda_codec_dev(codec), &eld->info, + eld->eld_buffer, eld->eld_size) < 0) { eld->eld_valid = false; if (repoll) { schedule_delayed_work(&per_pin->work, @@ -1555,7 +1555,7 @@ static void update_eld(struct hda_codec *codec, pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); if (eld->eld_valid) - snd_hdmi_show_eld(codec, &eld->info); + snd_show_eld(hda_codec_dev(codec), &eld->info); eld_changed = (pin_eld->eld_valid != eld->eld_valid); eld_changed |= (pin_eld->monitor_present != eld->monitor_present); -- 2.51.0 From 0ecd24a6d8b251ebd5c8f3a5cb7a9f07f989b132 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 24 Jan 2025 23:14:31 +0200 Subject: [PATCH 10/16] ASoC: hdmi-codec: dump ELD through procfs Use freshly added API and add eld#n files to procfs for the ASoC cards utilizing HDMI codec. This simplifies debugging of the possible ASoC / HDMI / DisplayPort audio issues. Signed-off-by: Dmitry Baryshkov Reviewed-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250124-alsa-hdmi-codec-eld-v1-2-bad045cfaeac@linaro.org --- sound/soc/codecs/hdmi-codec.c | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 69f98975e14a..497376bcd3ff 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -281,6 +281,7 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; uint8_t eld[MAX_ELD_BYTES]; + struct snd_parsed_hdmi_eld eld_parsed; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; struct mutex lock; @@ -288,6 +289,7 @@ struct hdmi_codec_priv { struct snd_soc_jack *jack; unsigned int jack_status; u8 iec_status[AES_IEC958_STATUS_SIZE]; + struct snd_info_entry *proc_entry; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -469,6 +471,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (ret) goto err; + snd_parse_eld(dai->dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); if (ret) goto err; @@ -825,8 +830,54 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +#ifdef CONFIG_SND_PROC_FS +static void print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_codec_priv *hcp = entry->private_data; + + snd_print_eld_info(&hcp->eld_parsed, buffer); +} + +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + struct snd_info_entry *entry; + char name[32]; + int err; + + snprintf(name, sizeof(name), "eld#%d", dai->id); + err = snd_card_proc_new(dai->component->card->snd_card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, hcp, print_eld_info); + hcp->proc_entry = entry; + + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ + snd_info_free_entry(hcp->proc_entry); + hcp->proc_entry = NULL; +} +#else +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ +} +#endif + static int hdmi_dai_probe(struct snd_soc_dai *dai) { + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; struct snd_soc_dapm_route route[] = { @@ -859,6 +910,15 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) snd_soc_dai_dma_data_set_playback(dai, daifmt); + return hdmi_dai_proc_new(hcp, dai); +} + +static int hdmi_dai_remove(struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); + + hdmi_dai_proc_free(hcp); return 0; } @@ -875,11 +935,18 @@ static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, static void plugged_cb(struct device *dev, bool plugged) { struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + int ret; if (plugged) { if (hcp->hcd.ops->get_eld) { hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); + ret = snd_parse_eld(dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + if (ret < 0) + dev_dbg(dev, "Failed to parse ELD: %d\n", ret); + else + snd_show_eld(dev, &hcp->eld_parsed); } hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); } else { @@ -926,6 +993,7 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { .probe = hdmi_dai_probe, + .remove = hdmi_dai_remove, .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, -- 2.51.0 From 1d5efdd4e76e8e81f150c243f6a663e60e091597 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Thu, 30 Jan 2025 19:08:22 +0100 Subject: [PATCH 11/16] ALSA: docs: Fix typo Signed-off-by: Jakub Wilk Link: https://patch.msgid.link/20250130180823.1864-1-jwilk@jwilk.net Signed-off-by: Takashi Iwai --- Documentation/sound/designs/powersave.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/designs/powersave.rst b/Documentation/sound/designs/powersave.rst index 138157452eb9..96f618b3f0b6 100644 --- a/Documentation/sound/designs/powersave.rst +++ b/Documentation/sound/designs/powersave.rst @@ -33,7 +33,7 @@ automatic power-save mode with 10 seconds, write to Note that you might hear click noise/pop when changing the power state. Also, it often takes certain time to wake up from the -power-down to the active state. These are often hardly to fix, so +power-down to the active state. These are often hard to fix, so don't report extra bug reports unless you have a fix patch ;-) For HD-audio interface, there is another module option, -- 2.51.0 From de7d2a70707ef991b8a2996ef1588f1e8b9aba95 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Thu, 30 Jan 2025 19:08:23 +0100 Subject: [PATCH 12/16] ALSA: docs: Fix module paths in /sys It's /sys/module/ (singular), not /sys/modules/. Signed-off-by: Jakub Wilk Link: https://patch.msgid.link/20250130180823.1864-2-jwilk@jwilk.net Signed-off-by: Takashi Iwai --- Documentation/sound/alsa-configuration.rst | 2 +- Documentation/sound/designs/powersave.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index 04254474fa04..a45174d165eb 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -58,7 +58,7 @@ debug 2 = verbose debug messages); This option appears only when ``CONFIG_SND_DEBUG=y``. This option can be dynamically changed via sysfs - /sys/modules/snd/parameters/debug file. + /sys/module/snd/parameters/debug file. Module snd-pcm-oss ------------------ diff --git a/Documentation/sound/designs/powersave.rst b/Documentation/sound/designs/powersave.rst index 96f618b3f0b6..ca7d1e838b4d 100644 --- a/Documentation/sound/designs/powersave.rst +++ b/Documentation/sound/designs/powersave.rst @@ -25,10 +25,10 @@ operations. The ``power_save`` option is exported as writable. This means you can adjust the value via sysfs on the fly. For example, to turn on the automatic power-save mode with 10 seconds, write to -``/sys/modules/snd_ac97_codec/parameters/power_save`` (usually as root): +``/sys/module/snd_ac97_codec/parameters/power_save`` (usually as root): :: - # echo 10 > /sys/modules/snd_ac97_codec/parameters/power_save + # echo 10 > /sys/module/snd_ac97_codec/parameters/power_save Note that you might hear click noise/pop when changing the power -- 2.51.0 From 2b360ba9a4936486380bc30d1eabceb40a714d98 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 8 Feb 2025 23:46:01 +0200 Subject: [PATCH 13/16] ALSA: hda: intel: Fix Optimus when GPU has no sound quirk_nvidia_hda() forcefully enables HDA controller on all NVIDIA GPUs, because some buggy BIOSes leave it disabled. However, some dual-GPU laptops do not have a functional HDA controller in DGPU, and BIOS disables it on purpose. After quirk_nvidia_hda() reenables this dummy HDA controller, attempting to probe it fails at azx_first_init(), which is too late to cancel the probe, as it happens in azx_probe_continue(). The sna_hda_intel driver calls azx_free() and stops the chip, however, it stays probed, and from the runtime PM point of view, the device remains active (it was set as active by the PCI subsystem on probe). It prevents vga_switcheroo from turning off the DGPU, because pci_create_device_link() syncs power management for video and audio devices. Affected devices should be added to driver_denylist to prevent them from probing early. This patch helps identify such devices by printing a warning, and also forces the device to the suspended state to allow vga_switcheroo turn off DGPU. Signed-off-by: Maxim Mikityanskiy Link: https://patch.msgid.link/20250208214602.39607-2-maxtram95@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7d7f9aac50a9..4155e010064b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1352,8 +1352,21 @@ static void azx_free(struct azx *chip) if (use_vga_switcheroo(hda)) { if (chip->disabled && hda->probe_continued) snd_hda_unlock_devices(&chip->bus); - if (hda->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) { vga_switcheroo_unregister_client(chip->pci); + + /* Some GPUs don't have sound, and azx_first_init fails, + * leaving the device probed but non-functional. As long + * as it's probed, the PCI subsystem keeps its runtime + * PM status as active. Force it to suspended (as we + * actually stop the chip) to allow GPU to suspend via + * vga_switcheroo, and print a warning. + */ + dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n"); + pm_runtime_disable(&pci->dev); + pm_runtime_set_suspended(&pci->dev); + pm_runtime_enable(&pci->dev); + } } if (bus->chip_init) { -- 2.51.0 From becc794c5e46f4dfca59f2385f78d83fc9e84700 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 8 Feb 2025 23:46:02 +0200 Subject: [PATCH 14/16] ALSA: hda: intel: Add Lenovo IdeaPad Z570 to probe denylist Lenovo IdeaPad Z570 with NVIDIA GeForce Ge 540M doesn't have sound on the discrete GPU. The HDA controller in DGPU is disabled by BIOS, but then reenabled by quirk_nvidia_hda(). The probe fails and ends up with the "GPU sound probed, but not operational" error. Add this laptop to DMI-based denylist to prevent probe early. DMI is used, because the audio device has zero subsystem IDs, and this entry would be too much, blocking all 540M chips: PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) Also, this laptop comes in a variety of modifications with different NVIDIA GPUs, so the DMI check will cover them all. Signed-off-by: Maxim Mikityanskiy Link: https://patch.msgid.link/20250208214602.39607-3-maxtram95@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4155e010064b..3f11f169fe4a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_X86 /* for snoop control */ @@ -2074,6 +2075,27 @@ static const struct pci_device_id driver_denylist[] = { {} }; +static struct pci_device_id driver_denylist_ideapad_z570[] = { + { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */ + {} +}; + +/* DMI-based denylist, to be used when: + * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards. + * - Different modifications of the same laptop use different GPU models. + */ +static const struct dmi_system_id driver_denylist_dmi[] = { + { + /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"), + }, + .driver_data = &driver_denylist_ideapad_z570, + }, + {} +}; + static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .position_check = azx_position_check, @@ -2084,6 +2106,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { + const struct dmi_system_id *dmi; struct snd_card *card; struct hda_intel *hda; struct azx *chip; @@ -2096,6 +2119,12 @@ static int azx_probe(struct pci_dev *pci, return -ENODEV; } + dmi = dmi_first_match(driver_denylist_dmi); + if (dmi && pci_match_id(dmi->driver_data, pci)) { + dev_info(&pci->dev, "Skipping the device on the DMI denylist\n"); + return -ENODEV; + } + dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); if (dev >= SNDRV_CARDS) return -ENODEV; -- 2.51.0 From 0f1f26c59196c785ced9f1a083ff350a6361c39f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 22 Feb 2025 12:41:29 +0100 Subject: [PATCH 15/16] ALSA: arm: aaci: Constify amba_id table 'struct amba_id' table is not modified so can be changed to const for more safety. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250222114129.162794-1-krzysztof.kozlowski@linaro.org Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index c3340b8ff3da..243965615ef2 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -1061,7 +1061,7 @@ static void aaci_remove(struct amba_device *dev) } } -static struct amba_id aaci_ids[] = { +static const struct amba_id aaci_ids[] = { { .id = 0x00041041, .mask = 0x000fffff, -- 2.51.0 From 604a0fe88db0ecef56ac38156a154945f4535ddf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Feb 2025 10:51:49 +0100 Subject: [PATCH 16/16] ALSA: pcm: Drop superfluous NULL check in snd_pcm_format_set_silence() We applied a fix for a KASAN issue for snd_pcm_format_set_silence(), and it introduced a NULL check of pat. But this turned out to be utterly superfluous; it points to pcm_formats[].silence, and this is an array, which can be never NULL. The problem (supposedly) it tried to address at that time was likely already fixed by another commit 8423f0b6d513 ("ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC") instead. So let's drop the superfluous NULL check again. While we're at it, keep the whitespace fix and move the pat assignment after the width check for a bit better code readability. Fixes: 2f7a26abb824 ("ALSA: pcm: Test for "silence" field in struct "pcm_format_data"") Link: https://patch.msgid.link/20250227095150.8187-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 4f556211bb56..d3a08e292072 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -432,9 +432,9 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int if (samples == 0) return 0; width = pcm_formats[(INT)format].phys; /* physical width */ - pat = pcm_formats[(INT)format].silence; - if (!width || !pat) + if (!width) return -EINVAL; + pat = pcm_formats[(INT)format].silence; /* signed or 1 byte data */ if (pcm_formats[(INT)format].signd == 1 || width <= 8) { unsigned int bytes = samples * width / 8; -- 2.51.0